From c26fea40019552a7e4fc1c864236f433b1b686f0 Mon Sep 17 00:00:00 2001 From: Shraddha Agrawal Date: Mon, 22 Jan 2024 19:14:36 +0530 Subject: [PATCH] attempt 5: read file in chunks instead of line by line --- README.md | 11 +-- main.go | 123 ++++++++++++++++++++++----------- profiles/cpu-read-chunk-2.prof | Bin 0 -> 15843 bytes profiles/cpu-read-chunk.prof | Bin 0 -> 17529 bytes 4 files changed, 88 insertions(+), 46 deletions(-) create mode 100644 profiles/cpu-read-chunk-2.prof create mode 100644 profiles/cpu-read-chunk.prof diff --git a/README.md b/README.md index 242e098..cf50625 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,9 @@ | Attempt Number | Approach | Execution Time | Diff | Commit | |-----------------|---|---|---|--| -|1| Naive Implementation: Read temperatures into a map of cities. Iterate serially over each key (city) in map to find min, max and average temperatures.| 6:13.15 | || -|2| Evaluate each city in map concurrently using goroutines.|4:32.80|-100.35| [8bd5f43](https://github.com/shraddhaag/1brc/commit/8bd5f437e8cc231e3ee18348b83f4dc694137546)| -|3|Remove sorting float64 slices. Calculate min, max and average by iterating.|4:25.59|-7.21|[830e5df](https://github.com/shraddhaag/1brc/commit/830e5dfacff9fb7a41d12027e21399736bc34701)| -|4|Decouple reading and processing of file content. A buffered goroutine is used to communicate between the two processes.|5:22.83|+57.24|[2babf7d](https://github.com/shraddhaag/1brc/commit/2babf7dda72d92c72722b220b8b663e747075bd7)| -|5|Instead of sending each line to the channel, now sending 100 lines chunked together. Also, to minimise garbage collection, not freeing up memory when resetting a slice. |3:41.76|-161.07|| \ No newline at end of file +|0| Naive Implementation: Read temperatures into a map of cities. Iterate serially over each key (city) in map to find min, max and average temperatures.| 6:13.15 | || +|1| Evaluate each city in map concurrently using goroutines.|4:32.80|-100.35| [8bd5f43](https://github.com/shraddhaag/1brc/commit/8bd5f437e8cc231e3ee18348b83f4dc694137546)| +|2|Remove sorting float64 slices. Calculate min, max and average by iterating.|4:25.59|-7.21|[830e5df](https://github.com/shraddhaag/1brc/commit/830e5dfacff9fb7a41d12027e21399736bc34701)| +|3|Decouple reading and processing of file content. A buffered goroutine is used to communicate between the two processes.|5:22.83|+57.24|[2babf7d](https://github.com/shraddhaag/1brc/commit/2babf7dda72d92c72722b220b8b663e747075bd7)| +|4|Instead of sending each line to the channel, now sending 100 lines chunked together. Also, to minimise garbage collection, not freeing up memory when resetting a slice. |3:41.76|-161.07|[b7b1781](https://github.com/shraddhaag/1brc/commit/b7b1781f58fd258a06940bd6c05eb404c8a14af6)| +|5|Read file in chunks of 100 MB instead of reading line by line. |3:32.62|-9.14|| \ No newline at end of file diff --git a/main.go b/main.go index db1356c..762e46a 100644 --- a/main.go +++ b/main.go @@ -1,11 +1,16 @@ package main import ( - "bufio" + "errors" "flag" "fmt" + "io" + "log" "math" "os" + "runtime" + "runtime/pprof" + "runtime/trace" "sort" "strconv" "strings" @@ -14,39 +19,47 @@ import ( var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`") var memprofile = flag.String("memprofile", "", "write memory profile to `file`") +var executionprofile = flag.String("execprofile", "", "write tarce execution to `file`") func main() { - // trace.Start(os.Stderr) - // defer trace.Stop() - - // flag.Parse() - // if *cpuprofile != "" { - // f, err := os.Create("./profiles/" + *cpuprofile) - // if err != nil { - // log.Fatal("could not create CPU profile: ", err) - // } - // defer f.Close() // error handling omitted for example - // if err := pprof.StartCPUProfile(f); err != nil { - // log.Fatal("could not start CPU profile: ", err) - // } - // defer pprof.StopCPUProfile() - // } - - evaluate() - // fmt.Println(evaluate()) - - // if *memprofile != "" { - // f, err := os.Create("./profiles/" + *memprofile) - // if err != nil { - // log.Fatal("could not create memory profile: ", err) - // } - // defer f.Close() // error handling omitted for example - // runtime.GC() // get up-to-date statistics - // if err := pprof.WriteHeapProfile(f); err != nil { - // log.Fatal("could not write memory profile: ", err) - // } - // } + flag.Parse() + + if *executionprofile != "" { + f, err := os.Create("./profiles/" + *executionprofile) + if err != nil { + log.Fatal("could not create trace execution profile: ", err) + } + defer f.Close() + trace.Start(f) + defer trace.Stop() + } + + if *cpuprofile != "" { + f, err := os.Create("./profiles/" + *cpuprofile) + if err != nil { + log.Fatal("could not create CPU profile: ", err) + } + defer f.Close() + if err := pprof.StartCPUProfile(f); err != nil { + log.Fatal("could not start CPU profile: ", err) + } + defer pprof.StopCPUProfile() + } + + fmt.Println(evaluate()) + + if *memprofile != "" { + f, err := os.Create("./profiles/" + *memprofile) + if err != nil { + log.Fatal("could not create memory profile: ", err) + } + defer f.Close() + runtime.GC() + if err := pprof.WriteHeapProfile(f); err != nil { + log.Fatal("could not write memory profile: ", err) + } + } } func evaluate() string { @@ -109,19 +122,24 @@ func readFileLineByLineIntoAMap(filepath string) (map[string][]float64, error) { chanOwner := func() <-chan []string { resultStream := make(chan []string, 100) toSend := make([]string, 100) + // reading 100MB per request + chunkSize := 100 * 1024 * 1024 + buf := make([]byte, chunkSize) + var stringsBuilder strings.Builder + stringsBuilder.Grow(500) + var count int go func() { defer close(resultStream) - scanner := bufio.NewScanner(file) - var count int - for scanner.Scan() { - if count == 100 { - localCopy := make([]string, 100) - copy(localCopy, toSend) - resultStream <- localCopy - count = 0 + for { + readTotal, err := file.Read(buf) + if err != nil { + if errors.Is(err, io.EOF) { + count = processReadChunk(buf, readTotal, count, &stringsBuilder, toSend, resultStream) + break + } + panic(err) } - toSend[count] = scanner.Text() - count++ + count = processReadChunk(buf, readTotal, count, &stringsBuilder, toSend, resultStream) } if count != 0 { resultStream <- toSend[:count] @@ -158,3 +176,26 @@ func convertStringToFloat(input string) float64 { output, _ := strconv.ParseFloat(input, 64) return output } + +func processReadChunk(buf []byte, readTotal, count int, stringsBuilder *strings.Builder, toSend []string, resultStream chan<- []string) int { + for _, char := range buf[:readTotal] { + if char == '\n' { + if stringsBuilder.Len() != 0 { + toSend[count] = stringsBuilder.String() + stringsBuilder.Reset() + count++ + + if count == 100 { + count = 0 + localCopy := make([]string, 100) + copy(localCopy, toSend) + resultStream <- localCopy + } + } + } else { + stringsBuilder.WriteByte(char) + } + } + + return count +} diff --git a/profiles/cpu-read-chunk-2.prof b/profiles/cpu-read-chunk-2.prof new file mode 100644 index 0000000000000000000000000000000000000000..1d434510d3d84d8f5c75b191a69799290e30c3ac GIT binary patch literal 15843 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