From c99a12b8115760d58a0f71fae6119cbd11c065bf Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Wed, 20 Dec 2023 21:47:11 +0100 Subject: [PATCH 01/36] WIP parallel --- cmd/catp/catp/app.go | 104 ++++++++++++++++++++++++++++++++++++------- cmd/catp/default.pgo | Bin 2350 -> 15778 bytes go.mod | 8 ++-- go.sum | 10 +++-- 4 files changed, 98 insertions(+), 24 deletions(-) diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index f23d1bd..a1e2ea8 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -11,18 +11,23 @@ import ( "os" "runtime/pprof" "strings" + "sync" "sync/atomic" "time" "github.com/bool64/dev/version" "github.com/bool64/progress" - "github.com/klauspost/compress/zstd" + //"github.com/klauspost/compress/zstd" + "github.com/DataDog/zstd" gzip "github.com/klauspost/pgzip" ) type runner struct { - output io.Writer + mu sync.Mutex + output io.Writer + pr *progress.Progress + parallel int sizes map[string]int64 matches int64 totalBytes int64 @@ -70,22 +75,47 @@ func (r *runner) scanFile(rd io.Reader) { s.Buffer(make([]byte, 64*1024), 10*1024*1024) for s.Scan() { + shouldWrite := true + for _, g := range r.grep { + shouldWrite = false + if bytes.Contains(s.Bytes(), g) { - if _, err := r.output.Write(append(s.Bytes(), '\n')); err != nil { - r.lastErr = err + shouldWrite = true - return - } + break + } + } - atomic.AddInt64(&r.matches, 1) + if !shouldWrite { + continue + } - break + atomic.AddInt64(&r.matches, 1) + + if r.parallel > 1 { + r.mu.Lock() + } + + if _, err := r.output.Write(append(s.Bytes(), '\n')); err != nil { + r.lastErr = err + + if r.parallel > 1 { + r.mu.Unlock() } + + return + } + + if r.parallel > 1 { + r.mu.Unlock() } } if err := s.Err(); err != nil { + r.mu.Lock() + defer r.mu.Unlock() + r.lastErr = err } } @@ -102,10 +132,17 @@ func (r *runner) cat(filename string) (err error) { } }() - r.currentFile = &progress.CountingReader{Reader: file} - r.currentTotal = r.sizes[filename] + cr := &progress.CountingReader{Reader: file} + + if r.parallel <= 1 { + r.currentFile = cr + r.currentTotal = r.sizes[filename] + } else { + + } + rd := io.Reader(r.currentFile) - lines := r.currentFile + lines := cr switch { case strings.HasSuffix(filename, ".gz"): @@ -116,9 +153,11 @@ func (r *runner) cat(filename string) (err error) { lines = &progress.CountingReader{Reader: rd} rd = lines case strings.HasSuffix(filename, ".zst"): - if rd, err = zstd.NewReader(rd); err != nil { - return fmt.Errorf("failed to init zst reader: %w", err) - } + //if rd, err = zstd.NewReader(rd); err != nil { + // return fmt.Errorf("failed to init zst reader: %w", err) + //} + + rd = zstd.NewReader(rd) lines = &progress.CountingReader{Reader: rd} rd = lines @@ -166,6 +205,7 @@ func startProfiling(cpuProfile string) { // Main is the entry point for catp CLI tool. func Main() error { //nolint:funlen,cyclop grep := flag.String("grep", "", "grep pattern, may contain multiple patterns separated by \\|") + parallel := flag.Int("parallel", 1, "number of parallel readers if multiple files are provided") cpuProfile := flag.String("dbg-cpu-prof", "", "write first 10 seconds of CPU profile to file") output := flag.String("output", "", "output to file instead of STDOUT") ver := flag.Bool("version", false, "print version and exit") @@ -229,9 +269,39 @@ func Main() error { //nolint:funlen,cyclop r.sizes[fn] = st.Size() } - for i := 0; i < flag.NArg(); i++ { - if err := r.cat(flag.Arg(i)); err != nil { - return err + if *parallel >= 2 { + sem := make(chan struct{}, *parallel) + errs := make(chan error, 1) + + for i := 0; i < flag.NArg(); i++ { + i := i + select { + case err := <-errs: + return err + case sem <- struct{}{}: + } + + go func() { + defer func() { + <-sem + }() + + if err := r.cat(flag.Arg(i)); err != nil { + errs <- err + } + }() + + } + + // Wait for goroutines to finish by acquiring all slots. + for i := 0; i < cap(sem); i++ { + sem <- struct{}{} + } + } else { + for i := 0; i < flag.NArg(); i++ { + if err := r.cat(flag.Arg(i)); err != nil { + return err + } } } diff --git a/cmd/catp/default.pgo b/cmd/catp/default.pgo index 699f91d80d86d656a962b72adf55de89cfb82fbb..b2390533b33decf14f326dc29a38482d8a297c22 100644 GIT binary patch literal 15778 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 gBYz8~z4cDCMKm{5SopX9Hvjyds zr6?e^Dx&UWcDxy7cV^kyO)!6IR6-yXkE%r~q^LRRY(=3 zsI5vLNTsL>(30xhnYGu%Hc|a!XXl>to$tHn<=y`9FaCD>3kUW;ok_%)0+B?FMIm%&@p%^FvlQ)37!xYMUMu!Cn`DO(2UJIDgF@2CRqctU<+>*A4bxxpaAJk#Fa=i7FU5a;JZgd`M-;S zl5VMa#2NyJMm%!Q%M`p3-e{7+8zF@$4&rE&3XI{;fBPFUGx&F)kU<-^@w9k7qIR+- zyyNT(5jDn|U`~y*1pG7(N;biopdH(JhuD`*vIMNbHM~=th^xR7_~7xEB5Ir^;m!t7 zvPqVN3}!frXXELX1#yk6DWL*O;tTKoirAaseMO3EhA!;l-Qqn(1=fs5|0>hh0w;pR zv_KE`@TB;5RL!s!{MPiXQ8ms|a3l!Q3cc9Nlj62$Hpx=Zhkd+X9Hxk^c<43> z0XP)+0u0~)?-%!xIfb|0`Y=UogZqMJXakO%4~qRU6&T>3-VXJACkl$%$=dMLX<0!j zA;!|MS>`7VDyn=)Y*K-x@u`ESDQG*~MVtxN4#POihs2ButR0^}CaoRt7qTW<2aMnd z9}>qEHN`scm6NBb0BayABd>u`9OY{TrEd*>aL?Toxf8w~6t5Em3O*+8Rni?0h4}-= zTNBA-b4zOq+S2VEYgAyJc<`eiMASITz`+2Nfh=bEpg2e^o55rC^N>!}YSz%1340Fl z(6Qxv4uhWS!Xw{!fOH|8A&LY;ScmKQ1!71A){TEY8P3dmktHqL)h&Cv2T#|!;sXWf zCSlhnd+KhIV!inO{s$;GUGP$xUUDzH90b@FSZp&K4b$kyrx9d*7z+()VF z#|Iyg<{mf|j71NO<2c_S9&c1rYyj_g>YEh07xFT6FBoX>3&j`J6yx~cJ68Nyo_HiPBg0hY%RX=>`^kS@Uo)D*$})LSL19L{zFwvG8H!A zCjM#h9IeSAxB{=>o5dUPY?2Mb7Tm%&i+5;g2t0ZFF_JI>ni^-L@FX>Mf{nmd+{(9! z_1PpFg(;lk{o=Zbg3T4Oo93N z`3TNGb2=hEbFtFh!6Gn!`0SJKoE^aVH|0}&w!51}$?wCn^rztb;o4VmwecyV(Km~w zg6$h|%d5H-BWjhZM$$E1&$lhl&H2W3-l^=a?$Ru;sP8G5Rlnr<72WcRrLyh&`fS0h z*qX@Z?Ano69@BPLXJ?D1yR|y&csp$~XP1pj^Q*<#ymwq1pVThWXDOcUxbiuZw_Ppo z8Jkwc1{h6zOoMCRT-jRitUbo$s_^BhiT2`EaVyZ$b&XcXlV7$}uC`6TVlcKu=G!+_ZP&7=Y|EdqZ?>&!#lFs=&X_TaxycFRl2wBcsjMCa(|!AKT343o1Z@h40wrAHIlDcka7Tlp2UT)D1Nw#{OACcDcpHm-VsrTn=d8r^%m z4z|nl3X>ChsqE!xOK2jyjn<3f=4(w&Ph)gt$RalH87+>dSzc*wYjt+kE*p)Gr)~2} zb4J?pwY=@xWyjiSo4M(-S2Plyug^LKn{e$OQBOMsdrT5elS5`#b=L9f=IaY(r($34 z8LiTw%TGdIwu(BdnA0t@Qj#B<$d;?FOS4)g8BW1A^z#MlW~oGM^-Jnw>06P_GAqXV z^Ci+gXF9IYR5Tq|qmLz9WJN~uBzeu{s#|f2b^uL_t<{HvFrsWUA|HthU?P3`0r4zUhNutA6?rn8-rnR zU5agIb0XdX9^3`o)=o<5q88xMO<_z0=&c5MXR2jv7}GghZ!m z_z-MhcyO+3OK8#d(Nq`%;j4a2_$3G$Dx=X1&x0v4GU4k&;Hv9L34IHhD0zi~=Hy+k z?6~IJ>-?9H##pErp-& zyFn|n>CAn$H)eYaP%^Om{W;$< U3xym17XSeN|2)Qbf;|!d0H_U_Q2+n{ diff --git a/go.mod b/go.mod index e48be65..e96467a 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,11 @@ module github.com/bool64/progress -go 1.20 +go 1.21 require ( - github.com/bool64/dev v0.2.31 - github.com/klauspost/compress v1.16.7 + github.com/DataDog/zstd v1.5.5 + github.com/bool64/dev v0.2.32 github.com/klauspost/pgzip v1.2.6 ) + +require github.com/klauspost/compress v1.17.4 // indirect diff --git a/go.sum b/go.sum index 8e4258d..4cdc86c 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ -github.com/bool64/dev v0.2.31 h1:OS57EqYaYe2M/2bw9uhDCIFiZZwywKFS/4qMLN6JUmQ= -github.com/bool64/dev v0.2.31/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= +github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/bool64/dev v0.2.32 h1:DRZtloaoH1Igky3zphaUHV9+SLIV2H3lsf78JsJHFg0= +github.com/bool64/dev v0.2.32/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= +github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= From ac9ad45a8c55579c78cedeb3ae4072c45a4ce218 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Thu, 21 Dec 2023 11:04:59 +0100 Subject: [PATCH 02/36] WIP parallel --- cmd/catp/catp/app.go | 104 ++++++++++++++++++++++++++------------ cmd/catp/catp/cgo_zstd.go | 13 +++++ cmd/catp/catp/zstd.go | 18 +++++++ go.mod | 3 +- progress.go | 82 +++++++++++++++++++++++++----- 5 files changed, 174 insertions(+), 46 deletions(-) create mode 100644 cmd/catp/catp/cgo_zstd.go create mode 100644 cmd/catp/catp/zstd.go diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index a1e2ea8..88ef973 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -17,8 +17,7 @@ import ( "github.com/bool64/dev/version" "github.com/bool64/progress" - //"github.com/klauspost/compress/zstd" - "github.com/DataDog/zstd" + "github.com/klauspost/compress/zstd" gzip "github.com/klauspost/pgzip" ) @@ -27,23 +26,27 @@ type runner struct { output io.Writer pr *progress.Progress - parallel int sizes map[string]int64 matches int64 totalBytes int64 + parallel int + currentBytes int64 + currentLines int64 + grep [][]byte currentFile *progress.CountingReader currentTotal int64 - lastErr error + + lastErr error } // st renders Status as a string. func (r *runner) st(s progress.Status) string { var res string - if len(r.sizes) > 1 { + if len(r.sizes) > 1 && r.parallel <= 1 { fileDonePercent := 100 * float64(r.currentFile.Bytes()) / float64(r.currentTotal) res = fmt.Sprintf("all: %.1f%% bytes read, %s: %.1f%% bytes read, %d lines processed, %.1f l/s, %.1f MB/s, elapsed %s, remaining %s", s.DonePercent, s.Task, fileDonePercent, s.LinesCompleted, s.SpeedLPS, s.SpeedMBPS, @@ -74,8 +77,15 @@ func (r *runner) scanFile(rd io.Reader) { s := bufio.NewScanner(rd) s.Buffer(make([]byte, 64*1024), 10*1024*1024) + lines := 0 for s.Scan() { shouldWrite := true + lines++ + + if lines >= 1000 { + atomic.AddInt64(&r.currentLines, int64(lines)) + lines = 0 + } for _, g := range r.grep { shouldWrite = false @@ -112,6 +122,8 @@ func (r *runner) scanFile(rd io.Reader) { } } + atomic.AddInt64(&r.currentLines, int64(lines)) + if err := s.Err(); err != nil { r.mu.Lock() defer r.mu.Unlock() @@ -132,7 +144,7 @@ func (r *runner) cat(filename string) (err error) { } }() - cr := &progress.CountingReader{Reader: file} + cr := progress.NewSharedCountingReader(file, &r.currentBytes, nil) if r.parallel <= 1 { r.currentFile = cr @@ -141,38 +153,37 @@ func (r *runner) cat(filename string) (err error) { } - rd := io.Reader(r.currentFile) - lines := cr + rd := io.Reader(cr) switch { case strings.HasSuffix(filename, ".gz"): if rd, err = gzip.NewReader(rd); err != nil { return fmt.Errorf("failed to init gzip reader: %w", err) } - - lines = &progress.CountingReader{Reader: rd} - rd = lines case strings.HasSuffix(filename, ".zst"): - //if rd, err = zstd.NewReader(rd); err != nil { - // return fmt.Errorf("failed to init zst reader: %w", err) - //} - - rd = zstd.NewReader(rd) - - lines = &progress.CountingReader{Reader: rd} - rd = lines + if r.parallel >= 1 { + if rd, err = zstdReader(rd); err != nil { + return fmt.Errorf("failed to init zst reader: %w", err) + } + } else { + if rd, err = zstd.NewReader(rd); err != nil { + return fmt.Errorf("failed to init zst reader: %w", err) + } + } } - r.pr.Start(func(t *progress.Task) { - t.TotalBytes = func() int64 { - return r.totalBytes - } - t.CurrentBytes = r.currentFile.Bytes - t.CurrentLines = lines.Lines + if r.parallel <= 1 { + r.pr.Start(func(t *progress.Task) { + t.TotalBytes = func() int64 { + return r.totalBytes + } - t.Task = filename - t.Continue = true - }) + t.CurrentBytes = r.currentFile.Bytes + t.CurrentLines = func() int64 { return atomic.LoadInt64(&r.currentLines) } + t.Task = filename + t.Continue = true + }) + } if len(r.grep) > 0 { r.scanFile(rd) @@ -180,12 +191,16 @@ func (r *runner) cat(filename string) (err error) { r.readFile(rd) } - r.pr.Stop() + cr.Sync() + + if r.parallel <= 1 { + r.pr.Stop() + } return r.lastErr } -func startProfiling(cpuProfile string) { +func startProfiling(cpuProfile string, memProfile string) { f, err := os.Create(cpuProfile) //nolint:gosec if err != nil { log.Fatal(err) @@ -199,14 +214,28 @@ func startProfiling(cpuProfile string) { time.Sleep(10 * time.Second) pprof.StopCPUProfile() println("CPU profile written to", cpuProfile) + + if memProfile != "" { + f, err := os.Create(memProfile) //nolint:gosec + if err != nil { + log.Fatal(err) + } + + if err := pprof.WriteHeapProfile(f); err != nil { + log.Fatal("writing heap profile:", err) + } + + println("Memory profile written to", memProfile) + } }() } // Main is the entry point for catp CLI tool. func Main() error { //nolint:funlen,cyclop grep := flag.String("grep", "", "grep pattern, may contain multiple patterns separated by \\|") - parallel := flag.Int("parallel", 1, "number of parallel readers if multiple files are provided") + parallel := flag.Int("parallel", 0, "number of parallel readers if multiple files are provided") cpuProfile := flag.String("dbg-cpu-prof", "", "write first 10 seconds of CPU profile to file") + memProfile := flag.String("dbg-mem-prof", "", "write heap profile to file after 10 seconds") output := flag.String("output", "", "output to file instead of STDOUT") ver := flag.Bool("version", false, "print version and exit") @@ -219,13 +248,14 @@ func Main() error { //nolint:funlen,cyclop } if *cpuProfile != "" { - startProfiling(*cpuProfile) + startProfiling(*cpuProfile, *memProfile) defer pprof.StopCPUProfile() } r := &runner{} + r.parallel = *parallel r.output = os.Stdout if *output != "" { @@ -270,6 +300,14 @@ func Main() error { //nolint:funlen,cyclop } if *parallel >= 2 { + pr := r.pr + pr.Start(func(t *progress.Task) { + t.TotalBytes = func() int64 { return r.totalBytes } + t.CurrentBytes = func() int64 { return atomic.LoadInt64(&r.currentBytes) } + t.CurrentLines = func() int64 { return atomic.LoadInt64(&r.currentLines) } + t.Task = "all" + }) + sem := make(chan struct{}, *parallel) errs := make(chan error, 1) @@ -297,6 +335,8 @@ func Main() error { //nolint:funlen,cyclop for i := 0; i < cap(sem); i++ { sem <- struct{}{} } + + pr.Stop() } else { for i := 0; i < flag.NArg(); i++ { if err := r.cat(flag.Arg(i)); err != nil { diff --git a/cmd/catp/catp/cgo_zstd.go b/cmd/catp/catp/cgo_zstd.go new file mode 100644 index 0000000..d00213e --- /dev/null +++ b/cmd/catp/catp/cgo_zstd.go @@ -0,0 +1,13 @@ +//go:build cgo_zstd + +package catp + +import ( + "io" + + "github.com/DataDog/zstd" +) + +func zstdReader(rd io.Reader) (io.Reader, error) { + return zstd.NewReader(rd), nil +} diff --git a/cmd/catp/catp/zstd.go b/cmd/catp/catp/zstd.go new file mode 100644 index 0000000..007bf79 --- /dev/null +++ b/cmd/catp/catp/zstd.go @@ -0,0 +1,18 @@ +//go:build !cgo_zstd + +package catp + +import ( + "fmt" + "io" + + "github.com/klauspost/compress/zstd" +) + +func zstdReader(rd io.Reader) (io.Reader, error) { + if rd, err := zstd.NewReader(rd, zstd.WithDecoderConcurrency(1)); err != nil { + return nil, fmt.Errorf("failed to init zst reader: %w", err) + } else { + return rd, nil + } +} diff --git a/go.mod b/go.mod index e96467a..ac963bc 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.21 require ( github.com/DataDog/zstd v1.5.5 github.com/bool64/dev v0.2.32 + github.com/klauspost/compress v1.17.4 github.com/klauspost/pgzip v1.2.6 ) - -require github.com/klauspost/compress v1.17.4 // indirect diff --git a/progress.go b/progress.go index 314f8a1..497b46d 100644 --- a/progress.go +++ b/progress.go @@ -232,56 +232,114 @@ func (p *Progress) Lines() int64 { return p.continuedLines } +func NewCountingReader(r io.Reader) *CountingReader { + return &CountingReader{ + Reader: r, + lines: new(int64), + readBytes: new(int64), + } +} + +func NewSharedCountingReader(r io.Reader, readBytes, lines *int64) *CountingReader { + return &CountingReader{ + Reader: r, + lines: lines, + readBytes: readBytes, + } +} + // CountingReader wraps io.Reader to count bytes. type CountingReader struct { Reader io.Reader - lines int64 - readBytes int64 + lines *int64 + readBytes *int64 + + readLocal int64 +} + +func (cr *CountingReader) SetLines(lines *int64) { + cr.lines = lines +} + +func (cr *CountingReader) SetReadBytes(readBytes *int64) { + cr.readBytes = readBytes } // Read reads and counts bytes. func (cr *CountingReader) Read(p []byte) (n int, err error) { n, err = cr.Reader.Read(p) - atomic.AddInt64(&cr.readBytes, int64(n)) + cr.readLocal += int64(n) + + if cr.readLocal > 100000 && cr.readBytes != nil { + atomic.AddInt64(cr.readBytes, cr.readLocal) + cr.readLocal = 0 + } + + if cr.lines == nil { + return n, err + } for i := 0; i < n; i++ { if p[i] == '\n' { - atomic.AddInt64(&cr.lines, 1) + atomic.AddInt64(cr.lines, 1) } } return n, err } +func (cr *CountingReader) Sync() { + if cr.readLocal > 0 && cr.readBytes != nil { + atomic.AddInt64(cr.readBytes, cr.readLocal) + cr.readLocal = 0 + } +} + // Bytes returns number of read bytes. func (cr *CountingReader) Bytes() int64 { - return atomic.LoadInt64(&cr.readBytes) + return atomic.LoadInt64(cr.readBytes) } // Lines returns number of read lines. func (cr *CountingReader) Lines() int64 { - return atomic.LoadInt64(&cr.lines) + return atomic.LoadInt64(cr.lines) +} + +func NewCountingWriter(w io.Writer) *CountingWriter { + return &CountingWriter{ + Writer: w, + writtenBytes: new(int64), + lines: new(int64), + } +} + +func NewSharedCountingWriter(w io.Writer, writtenBytes, lines *int64) *CountingWriter { + return &CountingWriter{ + Writer: w, + writtenBytes: writtenBytes, + lines: lines, + } } // CountingWriter wraps io.Writer to count bytes. type CountingWriter struct { Writer io.Writer - lines int64 - writtenBytes int64 + lines *int64 + writtenBytes *int64 } // Write writes and counts bytes. func (cr *CountingWriter) Write(p []byte) (n int, err error) { n, err = cr.Writer.Write(p) - atomic.AddInt64(&cr.writtenBytes, int64(n)) + atomic.AddInt64(cr.writtenBytes, int64(n)) for i := 0; i < n; i++ { if p[i] == '\n' { - atomic.AddInt64(&cr.lines, 1) + atomic.AddInt64(cr.lines, 1) } } @@ -290,12 +348,12 @@ func (cr *CountingWriter) Write(p []byte) (n int, err error) { // Bytes returns number of written bytes. func (cr *CountingWriter) Bytes() int64 { - return atomic.LoadInt64(&cr.writtenBytes) + return atomic.LoadInt64(cr.writtenBytes) } // Lines returns number of written bytes. func (cr *CountingWriter) Lines() int64 { - return atomic.LoadInt64(&cr.lines) + return atomic.LoadInt64(cr.lines) } // MetricsExposer provides metric counters. From fed3148ed5ffef4b90b162ed41cd702734487dc3 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Thu, 21 Dec 2023 15:27:28 +0100 Subject: [PATCH 03/36] WIP parallel --- cmd/catp/catp/app.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index 88ef973..97cb340 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -147,10 +147,10 @@ func (r *runner) cat(filename string) (err error) { cr := progress.NewSharedCountingReader(file, &r.currentBytes, nil) if r.parallel <= 1 { + cr = progress.NewCountingReader(file) + cr.SetLines(nil) r.currentFile = cr r.currentTotal = r.sizes[filename] - } else { - } rd := io.Reader(cr) From 15ad3967c5503cf234d0619f53ea5fa379403684 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Thu, 21 Dec 2023 16:48:56 +0100 Subject: [PATCH 04/36] WIP parallel --- .github/workflows/release-assets.yml | 2 +- Makefile | 1 + cmd/catp/catp/app.go | 128 ++++++++++++++++++--------- cmd/catp/default.pgo | Bin 15778 -> 16489 bytes 4 files changed, 88 insertions(+), 43 deletions(-) diff --git a/.github/workflows/release-assets.yml b/.github/workflows/release-assets.yml index bfb238b..5728ae9 100644 --- a/.github/workflows/release-assets.yml +++ b/.github/workflows/release-assets.yml @@ -8,7 +8,7 @@ on: - created env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GO_VERSION: 1.21.x + GO_VERSION: 1.22rc1 jobs: build: name: Upload Release Assets diff --git a/Makefile b/Makefile index 06f5916..69cd37b 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,7 @@ ifeq ($(DEVGO_PATH),) endif +export GOAMD64 ?= v3 export CGO_ENABLED ?= 0 BUILD_PKG = ./cmd/catp BUILD_LDFLAGS=-s -w diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index 97cb340..7e536fc 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -34,7 +34,8 @@ type runner struct { currentBytes int64 currentLines int64 - grep [][]byte + // grep is a slice of AND items, that are slices of OR items. + grep [][][]byte currentFile *progress.CountingReader currentTotal int64 @@ -87,11 +88,18 @@ func (r *runner) scanFile(rd io.Reader) { lines = 0 } - for _, g := range r.grep { - shouldWrite = false + for _, andGrep := range r.grep { + andPassed := false + for _, orGrep := range andGrep { + if bytes.Contains(s.Bytes(), orGrep) { + andPassed = true - if bytes.Contains(s.Bytes(), g) { - shouldWrite = true + break + } + } + + if !andPassed { + shouldWrite = false break } @@ -144,16 +152,22 @@ func (r *runner) cat(filename string) (err error) { } }() - cr := progress.NewSharedCountingReader(file, &r.currentBytes, nil) + var rd io.Reader - if r.parallel <= 1 { - cr = progress.NewCountingReader(file) - cr.SetLines(nil) - r.currentFile = cr - r.currentTotal = r.sizes[filename] - } + if r.pr != nil { + cr := progress.NewSharedCountingReader(file, &r.currentBytes, nil) + + if r.parallel <= 1 { + cr = progress.NewCountingReader(file) + cr.SetLines(nil) + r.currentFile = cr + r.currentTotal = r.sizes[filename] + } - rd := io.Reader(cr) + rd = io.Reader(cr) + } else { + rd = file + } switch { case strings.HasSuffix(filename, ".gz"): @@ -173,16 +187,18 @@ func (r *runner) cat(filename string) (err error) { } if r.parallel <= 1 { - r.pr.Start(func(t *progress.Task) { - t.TotalBytes = func() int64 { - return r.totalBytes - } + if r.pr != nil { + r.pr.Start(func(t *progress.Task) { + t.TotalBytes = func() int64 { + return r.totalBytes + } - t.CurrentBytes = r.currentFile.Bytes - t.CurrentLines = func() int64 { return atomic.LoadInt64(&r.currentLines) } - t.Task = filename - t.Continue = true - }) + t.CurrentBytes = r.currentFile.Bytes + t.CurrentLines = func() int64 { return atomic.LoadInt64(&r.currentLines) } + t.Task = filename + t.Continue = true + }) + } } if len(r.grep) > 0 { @@ -191,10 +207,12 @@ func (r *runner) cat(filename string) (err error) { r.readFile(rd) } - cr.Sync() + if r.pr != nil { + //cr.Sync() - if r.parallel <= 1 { - r.pr.Stop() + if r.parallel <= 1 { + r.pr.Stop() + } } return r.lastErr @@ -230,13 +248,29 @@ func startProfiling(cpuProfile string, memProfile string) { }() } +type stringFlags []string + +func (i *stringFlags) String() string { + return "my string representation" +} + +func (i *stringFlags) Set(value string) error { + *i = append(*i, value) + return nil +} + // Main is the entry point for catp CLI tool. func Main() error { //nolint:funlen,cyclop - grep := flag.String("grep", "", "grep pattern, may contain multiple patterns separated by \\|") + var grep stringFlags + + flag.Var(&grep, "grep", "grep pattern, may contain multiple OR patterns separated by \\|,\n"+ + "each -grep value is added with AND logic, akin to extra '| grep foo',\n"+ + "for example, you can use '-grep bar\\|baz -grep foo' to only keep lines that have (bar OR baz) AND foo") parallel := flag.Int("parallel", 0, "number of parallel readers if multiple files are provided") cpuProfile := flag.String("dbg-cpu-prof", "", "write first 10 seconds of CPU profile to file") memProfile := flag.String("dbg-mem-prof", "", "write heap profile to file after 10 seconds") output := flag.String("output", "", "output to file instead of STDOUT") + noProgress := flag.Bool("no-progress", false, "disable progress printing") ver := flag.Bool("version", false, "print version and exit") flag.Parse() @@ -273,18 +307,25 @@ func Main() error { //nolint:funlen,cyclop }() } - if *grep != "" { - for _, s := range strings.Split(*grep, "\\|") { - r.grep = append(r.grep, []byte(s)) + if len(grep) > 0 { + for _, andGrep := range grep { + var og [][]byte + for _, orGrep := range strings.Split(andGrep, "\\|") { + og = append(og, []byte(orGrep)) + } + + r.grep = append(r.grep, og) } } r.sizes = make(map[string]int64) - r.pr = &progress.Progress{ - Interval: 5 * time.Second, - Print: func(status progress.Status) { - println(r.st(status)) - }, + if !*noProgress { + r.pr = &progress.Progress{ + Interval: 5 * time.Second, + Print: func(status progress.Status) { + println(r.st(status)) + }, + } } for i := 0; i < flag.NArg(); i++ { @@ -301,12 +342,14 @@ func Main() error { //nolint:funlen,cyclop if *parallel >= 2 { pr := r.pr - pr.Start(func(t *progress.Task) { - t.TotalBytes = func() int64 { return r.totalBytes } - t.CurrentBytes = func() int64 { return atomic.LoadInt64(&r.currentBytes) } - t.CurrentLines = func() int64 { return atomic.LoadInt64(&r.currentLines) } - t.Task = "all" - }) + if pr != nil { + pr.Start(func(t *progress.Task) { + t.TotalBytes = func() int64 { return r.totalBytes } + t.CurrentBytes = func() int64 { return atomic.LoadInt64(&r.currentBytes) } + t.CurrentLines = func() int64 { return atomic.LoadInt64(&r.currentLines) } + t.Task = "all" + }) + } sem := make(chan struct{}, *parallel) errs := make(chan error, 1) @@ -328,7 +371,6 @@ func Main() error { //nolint:funlen,cyclop errs <- err } }() - } // Wait for goroutines to finish by acquiring all slots. @@ -336,7 +378,9 @@ func Main() error { //nolint:funlen,cyclop sem <- struct{}{} } - pr.Stop() + if pr != nil { + pr.Stop() + } } else { for i := 0; i < flag.NArg(); i++ { if err := r.cat(flag.Arg(i)); err != nil { diff --git a/cmd/catp/default.pgo b/cmd/catp/default.pgo index b2390533b33decf14f326dc29a38482d8a297c22..bc2dc77ae5d57a17a7dd663059de299bb2d9db3e 100644 GIT binary patch literal 16489 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 gBYz8~z4cDCMKm{5SopX9Hvj Date: Thu, 21 Dec 2023 16:52:37 +0100 Subject: [PATCH 05/36] dddddd --- cmd/catp/catp/app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index 7e536fc..b55e76a 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -175,7 +175,7 @@ func (r *runner) cat(filename string) (err error) { return fmt.Errorf("failed to init gzip reader: %w", err) } case strings.HasSuffix(filename, ".zst"): - if r.parallel >= 1 { + if false && r.parallel >= 1 { if rd, err = zstdReader(rd); err != nil { return fmt.Errorf("failed to init zst reader: %w", err) } From 99bd59ab3f9363524815d2d53ad8dc84beb3f675 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Thu, 21 Dec 2023 16:54:37 +0100 Subject: [PATCH 06/36] dddddd --- cmd/catp/catp/app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index b55e76a..7e536fc 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -175,7 +175,7 @@ func (r *runner) cat(filename string) (err error) { return fmt.Errorf("failed to init gzip reader: %w", err) } case strings.HasSuffix(filename, ".zst"): - if false && r.parallel >= 1 { + if r.parallel >= 1 { if rd, err = zstdReader(rd); err != nil { return fmt.Errorf("failed to init zst reader: %w", err) } From 9880f7acec82a165e73eb9f76f358bc632eeb668 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Thu, 21 Dec 2023 23:22:41 +0100 Subject: [PATCH 07/36] Revert no-progress --- cmd/catp/catp/app.go | 84 +++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 48 deletions(-) diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index 7e536fc..aa4ec92 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -152,23 +152,17 @@ func (r *runner) cat(filename string) (err error) { } }() - var rd io.Reader + cr := progress.NewSharedCountingReader(file, &r.currentBytes, nil) - if r.pr != nil { - cr := progress.NewSharedCountingReader(file, &r.currentBytes, nil) - - if r.parallel <= 1 { - cr = progress.NewCountingReader(file) - cr.SetLines(nil) - r.currentFile = cr - r.currentTotal = r.sizes[filename] - } - - rd = io.Reader(cr) - } else { - rd = file + if r.parallel <= 1 { + cr = progress.NewCountingReader(file) + cr.SetLines(nil) + r.currentFile = cr + r.currentTotal = r.sizes[filename] } + rd := io.Reader(cr) + switch { case strings.HasSuffix(filename, ".gz"): if rd, err = gzip.NewReader(rd); err != nil { @@ -187,18 +181,16 @@ func (r *runner) cat(filename string) (err error) { } if r.parallel <= 1 { - if r.pr != nil { - r.pr.Start(func(t *progress.Task) { - t.TotalBytes = func() int64 { - return r.totalBytes - } + r.pr.Start(func(t *progress.Task) { + t.TotalBytes = func() int64 { + return r.totalBytes + } - t.CurrentBytes = r.currentFile.Bytes - t.CurrentLines = func() int64 { return atomic.LoadInt64(&r.currentLines) } - t.Task = filename - t.Continue = true - }) - } + t.CurrentBytes = r.currentFile.Bytes + t.CurrentLines = func() int64 { return atomic.LoadInt64(&r.currentLines) } + t.Task = filename + t.Continue = true + }) } if len(r.grep) > 0 { @@ -207,12 +199,10 @@ func (r *runner) cat(filename string) (err error) { r.readFile(rd) } - if r.pr != nil { - //cr.Sync() + cr.Sync() - if r.parallel <= 1 { - r.pr.Stop() - } + if r.parallel <= 1 { + r.pr.Stop() } return r.lastErr @@ -319,13 +309,15 @@ func Main() error { //nolint:funlen,cyclop } r.sizes = make(map[string]int64) - if !*noProgress { - r.pr = &progress.Progress{ - Interval: 5 * time.Second, - Print: func(status progress.Status) { - println(r.st(status)) - }, - } + r.pr = &progress.Progress{ + Interval: 5 * time.Second, + Print: func(status progress.Status) { + if *noProgress { + return + } + + println(r.st(status)) + }, } for i := 0; i < flag.NArg(); i++ { @@ -342,14 +334,12 @@ func Main() error { //nolint:funlen,cyclop if *parallel >= 2 { pr := r.pr - if pr != nil { - pr.Start(func(t *progress.Task) { - t.TotalBytes = func() int64 { return r.totalBytes } - t.CurrentBytes = func() int64 { return atomic.LoadInt64(&r.currentBytes) } - t.CurrentLines = func() int64 { return atomic.LoadInt64(&r.currentLines) } - t.Task = "all" - }) - } + pr.Start(func(t *progress.Task) { + t.TotalBytes = func() int64 { return r.totalBytes } + t.CurrentBytes = func() int64 { return atomic.LoadInt64(&r.currentBytes) } + t.CurrentLines = func() int64 { return atomic.LoadInt64(&r.currentLines) } + t.Task = "all" + }) sem := make(chan struct{}, *parallel) errs := make(chan error, 1) @@ -378,9 +368,7 @@ func Main() error { //nolint:funlen,cyclop sem <- struct{}{} } - if pr != nil { - pr.Stop() - } + pr.Stop() } else { for i := 0; i < flag.NArg(); i++ { if err := r.cat(flag.Arg(i)); err != nil { From d0eeb74afe31e55ec60940915e62f7f46b605cd7 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Thu, 21 Dec 2023 23:31:54 +0100 Subject: [PATCH 08/36] Update profiles --- cmd/catp/bytesContains.pprof | Bin 0 -> 13654 bytes cmd/catp/default.pgo | Bin 16489 -> 13654 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 cmd/catp/bytesContains.pprof diff --git a/cmd/catp/bytesContains.pprof b/cmd/catp/bytesContains.pprof new file mode 100644 index 0000000000000000000000000000000000000000..7b30a451a1b74d581a64d626c2a4ff1b5c1797f8 GIT binary patch literal 13654 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
I~_+W3+vqCZp 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 oP;6vEPsA1x$qk!>;pmX z&D*Snnd%V~d0r6cAx|j7yeo{L(F-qc*1{gp@O^H}=a)0+)Cjp$2KG1P;|$EE>`;!`!w4f}(wyG%ai)5li9Yg$a?Dly zHqcKS7cq0dExdFV03uRaFlI6bLmiF9`b}iw0Q_y?BXy=*5QAFx1GrIP8P^^yckWD9+&0^u|<93hST74vyQuu_d((h0Urk0@9vAwnBI5C<3|odIlyB^y$^Yo8`@_pPl1FsTBl2eK=N{ zHGq9tA}<8+Lb@b%_4oq~q-!;#lS+os zLeebKF*)Xi9_aNnlr%nQM9(vg0Rj9UihvKV!Q{$AGc>QKk)%M#rMH;E0|D%9aam?y za@L~mjl7;*nP871-6lzQtxrLk;bz~K8#`V_4mKly`HAFM9paPStZKG3``FBpsCkr#sc}EIc*;; zLm_}6smxZGTweQz@Oqj{cDc}k-s`cDMQ(^EQzj4Opoz(T+g=r3qXlz92+>zcS%WOe zT4M73g_DKX6OybDTGCoY(u+yl9?(+K=Z#wnA!FR&w_i^Qo{1SVHb>YeGW=gq2r@g;vSH9edQt>{Ii`ooSc zaeaujXo3PZLaz`1xsX#-**L zzcz(@TEpCpI$$G^gUv8Ge%1itHS&3hAQaHR*QE{9wh+ihFDBP~Uf?wfSZ0LF=xZg) z_Zo_TAJ+>^o;tcL)0=UbTsq*x)|lM$_GiND3Cf)!Tu%K|>`Y(}@!{o|oc!?~;q_cD zy$>NmV-Iv^1w51WOU^btF$boFEkI6}s{^T{E-QTXg?)oso4RmDJ1f~w-xC>ivcSbMjup6jZk7tk zgV*=7?xeL_WXKx0g00yA zvoLvR!aviWLzkF=Kn`Ar$!Cwu5nkgi zOQO3eskAqc7syr%7ZDT9xHA8;9h$9)N_o`YS&6D_wpLKa38%; zhkCOy6O*f#wDcPHS!DOq_loRuX1{x}_$ZB`TjjodK z0Xi{LX3>io?pYBR<6r16p{va&!$EkEX7w1!o_7h(Zxi;wAMpJ)(g82QYv>wwz&3eV z@CW=W{WVl*zS|}ogum0=fzo;=4r?0rKy!Stv3$kEztP`9h2|F*1bj+=84o=8clPmI zc!)ku+BHTRh^g&AWT8O{t{d8D@DG~Hk<6vwf05nMc7D%4Bmu%d>4-AT4{RDt!E44p zEjVZj57W?I(j!}8W9b>crc|5fg;sbiT^qX247#2DVN1=A(CM#jlsHD{cIHQTUkLxA zT9(fP0qn`H<8uP*UoxH9Z`Jf753J`>_r3@J;^bkNB1a8F_d; zT_3u^T&v|}!5{HPx-oQWnQjghnqvy{vY<8I zLbrqp&F2fl2#?XM59LPkadA-6=Hsn&YpBqi8Vn;u>C17_ss%WwnS5M;x6y5(LUTOB zT?aa-&~Q<6S+v__Yv#Y(KNjsEQLKno_LP}36W>cOZSN_PrGgKNX)-H|jrp_$p$I15 zS$J;hR2xe%k%%1sWZY!t}GdYByjL!Q@&S!U@-Z=_X%4%~IDr*UO)A0}U!(nI%p z{L)RDLJ6(sxT-V9Wn)83_FCNDYm_kiT}G(f5YU+WzTUsfrlc})nxlCz`Sre_*QjO_=P1APG-Wl15o+iQ-UWyI01o#Y%*N!~ zzg*+>)Yy!>&>YS}>^n)X>YrUnvI|R?3tj1`B1>~I<%wOHEC^51^WANL9_;|MtMhr% z#@B8%rcQo#xo&i0em;1LW^;jTz?E2E+U!capY9J`WO@TWY>UYS)B9*%&r@+!WO1Xo1 zxg2bS$)&@Ky`KL{fr9Wqnzv4tIc@PYH*kP6tp=zqwxf0-zj>5ZZKnw1f1JF7kQDTj zvUOTcwZqwy6f7Y^cR@cYw=t#L*qk!D3)}uZ1pP8sy1wA?P#{~yr_n=bde{#=1szoR z=$Ms{8e?+jgs$Gqo~1OXPxv4`7`og1ghwtmz-ROkeOUs8euDNW?S!Rv>;@#GpOEJ9Lw`X_Yo&dx&NPst zh7q3rf{oD(1_+vZwp<+WVLm3uJhw%7Jp*i;3>36Td2Ehc)gEtT3{*B5BvNc(4?mKr^&0#zH|&9YeAUXZ*We@c zNT|>}*(lIRiCurN7$Sy>VM1n2KMWVN@eGw|nB<1jGhC|74lS7F!?SG`!>@<=w(y|r8C_yhM#rh*#I<5)7EqR1FyG4aD#LE}`eevN6Ism)lHJ{*K`g8Hifbrpv`yabbr#xECM z&p7D~K^QOSh^h}xJN1DN|A5IYr&bEDXS}3Dm>_8Ok9IwNM_S=H!KRof=z#L)3#9_= z-DOO)WDmk5LA!oC_HpTZlHf6pA0`XxuBLuJa@6}%ZByoCE9}ETm?CJ@?BVQZf5qFw z9{3yX=ho5-f5m^%zd|>dx8-HQ-|$g-G*oErX&xq+Drii9JL*rmq8?T4kvT<7m2rB(ESW6x5#!F0Nx-1&Rac3nif+771EDOIq<(IjPIbf?KhKN2NRX&w-GhPs~ zs`A4!K||cr!muBf3tFy@x8#H{pd_ldOe`1Hj4%i<3fiEi+y@+_a$@X7slOn+B>=A<;SQnG9Ys|3yGwd)$0 zxKM7DBoD%BLEGx^M5hK`Z4eV#8scGb^{AL*8H9`FqE+%ADs0!jW3l|Y;1x@2T#$|DqB+0g_`ixpj zvq5-W(55=~Zr2)~*X`xj2>SfXo{SE6;C0fU@4(0D@zBF&+i){@L(nAd!wt9-DQv)9 zc!jJO76m2go!FT=hsw-go)_-Iaw-o!Y!(Lm3YcMyctaHqYX$B6u{WdZ-8jlZ*SoQT zDnfB{B*)#Gg4Uky&d=|`sn%KLJy=PVA+I^g6ZXS8K_C4fpWlmvtmpUQ6ZAyLYfd%7 zepoN)yF>DMGaSW}a8iEmTPxla>%@AOx4$Lm1ZP`Di_MN59dCcj*3R347Jn;Ct^4pM z|3EmO(?NC`t-H-DbQ`_O!*)nn5j|obI9yX^izO=(?sty&JUuB00 z-W9a=XZg+pxUG>aj8|MB-+2IQs3ufse$Xh;P-!r0uy|X%Bi@xz;D`4F{W7x;E9pUe z-BRL%*oC@;x|%CkiSG+~`*}HO`8yuCRC4`0K1ol83eBCDhW+q?po53x;?41kCMaBB z@Sb>Ie89`NK6|{gn%Mf`LqW$>ILoTe3Fi+jr}M)GL1VTJVDTQp!Iq64!fw0hLc{(&2;=l{T`>FJQye3zepBxr)Nac>U_mkl?Fjp8Gh4G}&Tl$<xv*K#5vx%C7naL`$iGqK)rWs!cR}4n$ZwVfvem1`W+6vZDmQ;D`-+l91p_K|iZZH#sfSsl~sPna-8g8_5pB58DK->uy_j zwPjuP&Nj=sE#NCbCwt43`zS7L8}_8Prg_=$DE1K4Lxc*=g>7AR|5qFq;byR1&}Zx& zbq?inREg`^E_Z|QwV)*oG6pm{qon`ZruatC1~q)+QERsHGvgbpVc8*QI2XVkyM%Qm zxgD}88p+Bv>KGOW96+0Ie6e=|5HXzcH}oRasLG)@qH5H!4J zUE!}vksl;sGdM2jB_=$JE8FqxIWEcla6-_~Gqjn5$>ZCv_j*o9RU!N+XpVAaYt&*h zF@EH&_~E3W6G|b+xe-QHN@bq372=1V1igQTO>8!vpX5S*I3?)AX>#b&9_3Y~Y-o?Y z1oaZ3-oh*m`{A^pU5D*S`g8SA1R5zO^-qb@B9&=_@Ux&bs&q?BLdsWuW(5R%Xdg0U zd}gHqgkJ=$<{Zsq6l-X$T<{l*gy2^}YbVRJ^B8`~X~!pLmwDOn81@m=httkhP8@bV z^L{RV750TJf}}>htOOs$LweW)58(jLEp7XuyG9%L z%2XA`k9m&aU7i(Jv93Dw5%2G!R1^FIfR}XEl#(x0<4~z9CG&3 zXb8u?3q}<@^wR3dbB^8`)heft$)TL>#zt@EfzU^z)x%`Dk;^yC0?v_YAMGOMLC{yD z@!!a;-HcmXrh4l@1I5eRS5u9$D_Ve`M#d=GCrFY@n3D4}&!N;(bX8 zxHKK621$}24AyA7YIxGz*jB7(uv|3=Lo`~`SAdJ#zohp>}xzm_Jkx`P+52H2e zb%viRWsPR727Jn783V0=_QM#B)+rPmZCOIG9mDVNNK>OpXRuWyV z=F584_PLC4njFUYVZ261)I#<}8YSF#$;A&7H2PK@;!V$x=dLzpWlqqngEfMQ8uhK? zG}u+MPt>e4T0czEXtuiE)RUV!=X%p5%^F=0Ox9?r1xJV`udzJb#w3*r+s$C1h zERCM6Gv;l2&n(;LW^1%-jUCByChm+~X3H%GVU9-6a=zyP{nhQiwvTw`NM6n1S&e3o zbPbG)@i^Znj^XO2DDrZk7zYR%AVLF$`GY4f8)7&}&>-I3il$*d%+=`7VY_HN#@(r7 z?Ps;QQj30=r&0GaoZ0p<&patF!hDT}skvgIbY^?g8S^#!Xrlk~6wk7JQss}zR`8pfO^>Us6yaU3paxClLF zwh#MZiAIMe$dzxy?>N>kRPNZsI;L5mJ*O?y7HNyMC0c6M=!c~mt+OH|RaDyP-Lurz z+4CCpU1A?f@m1(-#o2hCofF{&jrLlH=t7={W-Fx{FED{0mT9zS&nCuR56;)+#V=d! zuuRLaf)!!8M&s&cv)p3yqDI?K^kz1lWoF6ChR!%b&4=XfUc0$%W7vOqUnN#Vn(D*Rq5?HCx?gP>n%5XU^T#n2buz%)iTih@UlkJ)%i^i*0nS6cv-WG{UE%e(Rx)! zx(=V5+Xt`M++NjaWZKxp$(pZf&e*I4yr$6{Ys`>3L+DfIwBa=;Pa@Q6G)ry$CggI+ z4p{FdQL8rZhu1Ya{+bO$XXKaHZ6{r$(J-Bc5q`;CkySy|d{xVr{BaKzLK5bxQpE(=7L> zWvsIjXb{$GbX-Al+PS{6?s{ntgts)BplVU8Yq6u%c#F3ggts;NMpaB{0~N*TZJX0O z8ZC9-@^k$19ZBJbcQyL9k3BaT!Wq`7Yv0vmN+ftsqgm<%ehZg{)(O1pGQoQ+S95q@ zqrHsHhJCmCY`OD&X-_|VpwX%~(oL>*@PQ;j_)w$itXKou$P0CjcpqANMcAOx!n!xP z!QSLXjrOY>t7Ez6aLzzBYEI7lNTW@vPCMWZKigkDA4z^e_*kPoDo%H}36=C8OG1QC zGe+S|gI83?N1bFBV2bxE`ZY}M$k#S+x(`eKC3N49D_F%1XdOO1~7m8W)b zY!LQ9CC;$=);Nw4G)9ER3Nw(G4V5@f&^XSw(|I7hO{34$sqH*gsZ)`BscqBv#1`Qz zjV3D>?Uq(4ipV+X zP}kMjYIY)j) z$dPo9l++JB31_Ao2*m^L-*Pw`!w34xY#Y2y&KOyn`FO6tJJCTI_Bcc1opct zwF4S`q!QRZ-i>3z1DYH&G>3y4?fkvCRBIpPwF9}zJlT(r&}y|*6#3zhM&ojEm+x#I#wm;9v__v< zXRV!a6(x*j@BOV66N20T4< zo_YD9r%oHsqJo}!dXvxsdg-*ahrG60jS}}R!ROmJUoXgkYMdl!k_b%}<}l55^4Uw5 z7cZJYZ=EJ`i+q;RwbE8^DP0TbqthNM2iD-~x=x~MaEhQQjIb;DBuc&CN4G`^eRW!s zzJFVpp1yL0AoSCzk1GD_blQHBkf6U#vn^51yr`*I_LqzLVSrA{)$oD82;(Y52I$U} za)g08eX9Cz?j@a*;(@yCzk@JHrsy2ghU&EBlhF*_UGYeZum_&RMSN164P9}XplM9_eT%#t zcoL@znl3^!gt>-0{9!tsd`b52-EcQwz|4kjI8)F}?%!WCT+lUGAEFP{hcPY<*Xd<- zc~LZ^9Wpq$$G2=;JS8v2J+7{W-Mb|{?|$?&n?$QUVg>Z(i**qx3a zM(MQssO*&Q#jgxxt&P@ca@utu=c>UdeZ3g1TaCIO#^{th%RR_3EMpj9tWG0UNH>x) z*)EeY)(UBaaXL*?wb4_OM2S64lDG<;=5|gVuhU0|ZK0ddKVQMWH1i!UUaO zQi$`AEFo;x#spnX{U_>_oYjZT{~)g6uZI#$(rK%@eDRfY`NGu?Ow`{OlWd2dtkb?; zGPzY*Fxp5#WBti`T5_AB(}aUk=4N<;GmVpV`QpM9-PUWsr#NIxRQCj?>NHV(cVPyD zwNqeB)w#m-!!(_0_sP-JWw;U2#(vXu*Gw8=x=z!r8eG_|qkYg}OlPGa%+P6TI)T#K z3|(V$*t+&yF3mwOQ>RmEEPl*27H^;^y)$*!P<)n7i|g#66yI4K*sd~xX8^9EWVTK( zs02ATT^qC6?OYnHwKPaDN2gjVoZ8|s?oU(47HZKs{A!rsS)D!|CNaaVY@fneJethr z9|X-}M3^B*kve^QNWxBY{LC6f+PpHK)#uv&F;AzXbL2SgRvf}scZ#2Ry6duE3z)Cd ziL+PKE{o5XtO*wAG)rBiJyqvad4Wy&oKE|`ly`2P#us_o`VjWFTAQbFwxHR3Bsb0D zIz4+%-{?3bk27`Jbe6_qp{=$>I=yb4Za#xwa6q-UzGagQ&)^(Eb9g59x#n{EMfz#s zw5AA)b(*GP_3tuPZEYHh*)0i{=rrv2Q~weviyxNiG|MvfZ!RA!l_Uty>oiV*PFD#! zs-k&bf=<{EFX;4@`l^Wh?uIiFctKaaGQu*Q-c+c2r{rYIov}=!F5j=zY2H!^5{
I~_+W3+vqCZp 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 Date: Thu, 21 Dec 2023 23:32:32 +0100 Subject: [PATCH 09/36] Use Boyer-Moore strings finder --- cmd/catp/catp/app.go | 10 +-- cmd/catp/catp/search.go | 122 +++++++++++++++++++++++++++++++++++ cmd/catp/catp/search_test.go | 41 ++++++++++++ 3 files changed, 168 insertions(+), 5 deletions(-) create mode 100644 cmd/catp/catp/search.go create mode 100644 cmd/catp/catp/search_test.go diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index aa4ec92..770ec5b 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -3,7 +3,6 @@ package catp import ( "bufio" - "bytes" "flag" "fmt" "io" @@ -35,7 +34,7 @@ type runner struct { currentLines int64 // grep is a slice of AND items, that are slices of OR items. - grep [][][]byte + grep [][]*stringFinder currentFile *progress.CountingReader currentTotal int64 @@ -91,7 +90,7 @@ func (r *runner) scanFile(rd io.Reader) { for _, andGrep := range r.grep { andPassed := false for _, orGrep := range andGrep { - if bytes.Contains(s.Bytes(), orGrep) { + if orGrep.next(s.Bytes()) != -1 { andPassed = true break @@ -299,9 +298,10 @@ func Main() error { //nolint:funlen,cyclop if len(grep) > 0 { for _, andGrep := range grep { - var og [][]byte + var og []*stringFinder for _, orGrep := range strings.Split(andGrep, "\\|") { - og = append(og, []byte(orGrep)) + sf := makeStringFinder(orGrep) + og = append(og, sf) } r.grep = append(r.grep, og) diff --git a/cmd/catp/catp/search.go b/cmd/catp/catp/search.go new file mode 100644 index 0000000..ece593e --- /dev/null +++ b/cmd/catp/catp/search.go @@ -0,0 +1,122 @@ +// This file is a []byte conversion of https://raw.githubusercontent.com/golang/go/master/src/strings/search.go. + +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package catp + +import "strings" + +// stringFinder efficiently finds strings in a source text. It's implemented +// using the Boyer-Moore string search algorithm: +// https://en.wikipedia.org/wiki/Boyer-Moore_string_search_algorithm +// https://www.cs.utexas.edu/~moore/publications/fstrpos.pdf (note: this aged +// document uses 1-based indexing) +type stringFinder struct { + // pattern is the string that we are searching for in the text. + pattern string + + // badCharSkip[b] contains the distance between the last byte of pattern + // and the rightmost occurrence of b in pattern. If b is not in pattern, + // badCharSkip[b] is len(pattern). + // + // Whenever a mismatch is found with byte b in the text, we can safely + // shift the matching frame at least badCharSkip[b] until the next time + // the matching char could be in alignment. + badCharSkip [256]int + + // goodSuffixSkip[i] defines how far we can shift the matching frame given + // that the suffix pattern[i+1:] matches, but the byte pattern[i] does + // not. There are two cases to consider: + // + // 1. The matched suffix occurs elsewhere in pattern (with a different + // byte preceding it that we might possibly match). In this case, we can + // shift the matching frame to align with the next suffix chunk. For + // example, the pattern "mississi" has the suffix "issi" next occurring + // (in right-to-left order) at index 1, so goodSuffixSkip[3] == + // shift+len(suffix) == 3+4 == 7. + // + // 2. If the matched suffix does not occur elsewhere in pattern, then the + // matching frame may share part of its prefix with the end of the + // matching suffix. In this case, goodSuffixSkip[i] will contain how far + // to shift the frame to align this portion of the prefix to the + // suffix. For example, in the pattern "abcxxxabc", when the first + // mismatch from the back is found to be in position 3, the matching + // suffix "xxabc" is not found elsewhere in the pattern. However, its + // rightmost "abc" (at position 6) is a prefix of the whole pattern, so + // goodSuffixSkip[3] == shift+len(suffix) == 6+5 == 11. + goodSuffixSkip []int +} + +func makeStringFinder(pattern string) *stringFinder { + f := &stringFinder{ + pattern: pattern, + goodSuffixSkip: make([]int, len(pattern)), + } + // last is the index of the last character in the pattern. + last := len(pattern) - 1 + + // Build bad character table. + // Bytes not in the pattern can skip one pattern's length. + for i := range f.badCharSkip { + f.badCharSkip[i] = len(pattern) + } + // The loop condition is < instead of <= so that the last byte does not + // have a zero distance to itself. Finding this byte out of place implies + // that it is not in the last position. + for i := 0; i < last; i++ { + f.badCharSkip[pattern[i]] = last - i + } + + // Build good suffix table. + // First pass: set each value to the next index which starts a prefix of + // pattern. + lastPrefix := last + for i := last; i >= 0; i-- { + if strings.HasPrefix(pattern, pattern[i+1:]) { + lastPrefix = i + 1 + } + // lastPrefix is the shift, and (last-i) is len(suffix). + f.goodSuffixSkip[i] = lastPrefix + last - i + } + // Second pass: find repeats of pattern's suffix starting from the front. + for i := 0; i < last; i++ { + lenSuffix := longestCommonSuffix(pattern, pattern[1:i+1]) + if pattern[i-lenSuffix] != pattern[last-lenSuffix] { + // (last-i) is the shift, and lenSuffix is len(suffix). + f.goodSuffixSkip[last-lenSuffix] = lenSuffix + last - i + } + } + + return f +} + +func longestCommonSuffix(a, b string) (i int) { + for ; i < len(a) && i < len(b); i++ { + if a[len(a)-1-i] != b[len(b)-1-i] { + break + } + } + return +} + +// next returns the index in text of the first occurrence of the pattern. If +// the pattern is not found, it returns -1. +func (f *stringFinder) next(text []byte) int { + i := len(f.pattern) - 1 + for i < len(text) { + // Compare backwards from the end until the first unmatching character. + j := len(f.pattern) - 1 + for j >= 0 && text[i] == f.pattern[j] { + i-- + j-- + } + if j < 0 { + return i + 1 // match + } + + i += max(f.badCharSkip[text[i]], f.goodSuffixSkip[j]) + } + return -1 +} diff --git a/cmd/catp/catp/search_test.go b/cmd/catp/catp/search_test.go new file mode 100644 index 0000000..8d8cd20 --- /dev/null +++ b/cmd/catp/catp/search_test.go @@ -0,0 +1,41 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package catp + +import ( + "testing" +) + +func TestFinderNext(t *testing.T) { + testCases := []struct { + pat, text string + index int + }{ + {"", "", 0}, + {"", "abc", 0}, + {"abc", "", -1}, + {"abc", "abc", 0}, + {"d", "abcdefg", 3}, + {"nan", "banana", 2}, + {"pan", "anpanman", 2}, + {"nnaaman", "anpanmanam", -1}, + {"abcd", "abc", -1}, + {"abcd", "bcd", -1}, + {"bcd", "abcd", 1}, + {"abc", "acca", -1}, + {"aa", "aaa", 0}, + {"baa", "aaaaa", -1}, + {"at that", "which finally halts. at that point", 22}, + } + + for _, tc := range testCases { + sf := makeStringFinder(tc.pat) + got := sf.next([]byte(tc.text)) + want := tc.index + if got != want { + t.Errorf("stringFind(%q, %q) got %d, want %d\n", tc.pat, tc.text, got, want) + } + } +} From e3756d24cbc4089a27a058f55821da9ca5020d17 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Thu, 21 Dec 2023 23:42:58 +0100 Subject: [PATCH 10/36] Update PGO --- cmd/catp/default.pgo | Bin 13654 -> 10770 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/cmd/catp/default.pgo b/cmd/catp/default.pgo index 7b30a451a1b74d581a64d626c2a4ff1b5c1797f8..35a91ac6eaff495b4e5fdefaacd591ec5b607511 100644 GIT binary patch literal 10770 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 Q00030|CiUL!{Af^06t(YmH+?% literal 13654 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
I~_+W3+vqCZp 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 o Date: Sat, 23 Dec 2023 21:26:56 +0100 Subject: [PATCH 11/36] Revert "Update PGO" This reverts commit e3756d24cbc4089a27a058f55821da9ca5020d17. --- cmd/catp/default.pgo | Bin 10770 -> 13654 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/cmd/catp/default.pgo b/cmd/catp/default.pgo index 35a91ac6eaff495b4e5fdefaacd591ec5b607511..7b30a451a1b74d581a64d626c2a4ff1b5c1797f8 100644 GIT binary patch literal 13654 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
I~_+W3+vqCZp z!b+V6aZSS0#M5p2#gDR_m|k^}_@&>$Ffo%y)G{%*zhMTmrA?bnW1A4ZonMJcr}$85MI-1m~yci z=@>S*jMtQl)#}u5vjpvqxHc0-ps8}629MY3znRh#yslFp)!3xRyv^J5x{P^*H9Boj zZuxN9>T9HzxGFQ*^w|SuKfIyS{LvDzuE*(&uFme>(ADW^5Z3B6R)P3tx98a2?^!D? z*Bsu|>Co@BqDt^LWn}tcolY~pmpZu&Po*cab?!vwhxIz`K4fRq(Od;M?c#d9(5eCa z@Rm;Rt(AEGKU~^UPU-)L^99XkAfM7QOz^f&>y&TpbNQBY`{FJAZO6L^-qGohHRC?> zDxJM~?>laPc~_?|&H^OwrhtUtJ)J(^FY`$S_9#r9D!7pUJ!#tjysy(cTLx+23`h!` z#z^ktpB4yOAVSXxbCM?Mj%%cNe%&&_WS<*nB430zTB~L+h-lhd>_E z_Y~MI?19_lw_5VD`Qt@`7Ku=q*)lJiA1@ZPm|uS~5LBDZd0+oP|4?_GC2i2@p!;tM zxm;+2uKsk7A2#YVjXlG4<-*pVXQS;5AL+DFRW%=_JHtom&hW8L;}*z9UZ9+=JEv10 zbN=wdCpz^%3krW?p)kRxI*n2%wY!|0$|F{t#;R80>lSI(Vn5Zd{miQHgYdad+qvsv zK;2eXSbQ$SA^>0LG;zROHcu~sCwa7z!#^z%w1g)oKQj8*+VD=+ztF8j;nL*osgqnk zY|?3;I#i!!9je>!W^U50L-kzPtkVfA!CrywWD}l1Zo+L!V>7D>VT(>f)Ev?}Kv4u+ zEP|~%t=v0}&qfMmz3$YaTkTr(OPvl_=xcp*#D)G}I&l<)Z947!UG(23mF0)8boxw9 z&(1ja`O5Z`?Kka{meWygmw?B&Ep>W#g1o^{4>?&m_377o>JQi;e4|tCQ2QFs zA0%|z8p!xYm-97(9XfqHPJ&8rfmek+P=HgLNo?sYaH*iBT<&mJZolc-q4PJ&{qU_$ z1Ki)fa2fPleYyQr3xb_G9jp76jbgY{?weqjPUHGYNlf=2FK}69mqZOee5cdOvy64W z)8#RaA9m|BDNQ`TS`c0 z(^qE=Y*9Qv zNkTuI(rJq7rsWxkBi<>g8HCe19Zxrb&BQp(Ch)`0I{mC1?+irx+4h)UbQ-f$=JVz_ zIQ<&+FLG}Lzv^^ARUXIEDi3?P`oHS6?$$SH(0+A=eQkOtku+oshoHMb8@Q3ofW87> zvnGe`vzZ+J`~^WTu&=!82C44GwbxxAZVo*R+RUBS|8+*&!>A`mtvwBz#s!W620oLP z8hfVNen0dwXu2xIrtqIIa4Lvi#@p_F2B5b=U#}R!9^OyjJih0Y!#^z(w2Y;m(K;M} zJ_hx&X!;ABV$t*$xLnY3rWw~d?1#Pvo!V#HU;y{%PBGit=wtMi8xBA}gI0YxjF%fA za3;x%NCO1EDCk9IHJZYH=x@-(SrTYl;0MjqfaLLhMt|cvKGqsw&|-C*uqE9-0}N>& zKMXWzxMH-P89CQv23lMO8MIg(Db8RRaU67zVU2qR8}v(G2}hY|{}nUaWikd^3n2_K z=yNOK3;FF?XPqI2wA)aFmi3l@fx`L&Kh82kjRtZ)Hq4;mAKAwhThk>OCXL@1h8uK< z!N>yx1vUz2FcL{j%H|JV67&-1!iFvY8g3lpFiY=1T#horpr3}xy=AByefHimM;KOF zAA*qvEj=bZWRSpD_yqD&oXSl<}LUD+r?v8moY%&N=yLTU%oc+BIep4?l8o0XK#Y=#DX3OY;X|tU+59x5IVe z*;t#~ID>X^RC(;bSnBfKaVc#Pj5p}S@0SYWrKJKe!JyAl9l=0>A{>H=27NwPdbPU+ z$bi8DXYjy0hksfrXeFz0dJDd9X;8lf@{JI_#D%c4$qB|pW0G-wI0%ysTB|l$Cl*h( zH#x;VX8sf)E(NiVTSD#o~g{MNkcCDYm*u!xA)aU$!pD3;wsUkF=&{a zc68-?J6ce3`?6Ka+>}Cz6?nmRFX=5)n^Pyr!Z$q8C-xM6xQP74bx@C|*&Vi2S9bw7OGG zhy0>=c|nJGyzI&=3M#AOB~`IRqM)d}xS%LnU0F~Rt**>B^QvkpDq>Zw@)JeTiknNz zVv#=;bc&b93OYoKI>#!C+gHb;$!9l+ z+<0Ehp0eMyxY>Fri90;mr6O0K7f;2qrlM5tw^_=7mGQE&{L+$&cvWdd$xXN2{lNXV z-E)q+PvcS0u{gz@(w^j-c{kr^1wzCZPw=m$WwBP4YTBIBHsXnbj-_R>_LcF3CBK`G zR7b)2@L_FcmsS+Vp6t-AI@Tdx+%0m;IlZ6S7rz%RD=A1ZvCWi-`1nyG|2F1+eYfgZ zr0|?L%eSomvvgVVcZ*9T$NJ@lctv%zv?AfaVR@{)Jl-XCj=rE`&VDN;aklLo`CY3@ zt7Fcu56NE}r}iv8#j>UK2wlds-gSRs(fA~QNW{6bv?7*>1Z^=G%WvouE9!i2T&@sl zs2+4Itth^~rlKO+p)3};;+(W+zgkdP6)$4-q5VOAqNr1>xTY)?$x)wFMyoovFOOua z-^&@kB3GT)G7M5Fcv6gFPnK5Onshel`mkd(QLXHH(-Sq(GDoJGL|H6W8TspZ36bcQ zNJEH(v+JswiYH2{q8%cBB^-Z}sE$R;oR8$M55=oGyTX+nEm~HRe?v`myi2U=9Dz&P zkCTD@x)l|+hDzd*%WNqe!f188ytF9a%zLo3qWa1!TIJsmFRzSN#jdL;Zr3$h8M*1a zG?7~0Vq1_(&rR)x^Ub`n((=;kSk+BkVinb`@)OnZ%JZ~&c}bDv!5d1sS7m8&S*#>h z9U--n`lMZDX+=e8MTz5RU89|2m61k@uqu{_RVNfxKz&>kO_U_6qt!JD$5QOo-AZF+ z#heQ(irARdrRA~q#c^IGlAGWU&Ahv6s$);K$}fu-b#7M{?|P02o?k8~=T~`W0shtD zb!WV&bEIB*tUUIFM9CY@$u22-D1V5tyW9Sdh%`C#xdn3)EXjfkSFI8)?h>siibW`0 zvYLw2J{zV#c~Cxa^xl#87Do?OQs2^HaaFwXhWjIp zZBF@SULsZ=y+0nWZk7K;O|0g8v6bIuQB#`a4~m|sDXofK9%(9VU@z6aU98-GB7O4r zcEbR0RV!;Z7uoOEvFYpM@iLn#*QUy^ip97JRhXN~A8DUnps3y3FOFFXaBrn5Ru+pU zVwXpPXKuxQ;&>FBF5;}mzdlr2-Rb^lMd$NO#r$ejw4!tSc*l;c+xkjce&Cpn0nJX6 ziTsM#lhx-4%r>`z@(!id<#9l|sFKcWWv*17;c&1%auV#l(JEIsGW3?G8i{-}ue>N))G5{~zp^UEDd6UKRlBa7 z4X-?}aI(0t4pZQ4yPykmODk@TMJw;AYF8aC>U@r+r>&xb@=md+?0i%HS5y+eEpba+ zDJ$iFQFfqvt75V8%IfpU`!o6g ztGbi5oP_>d3rbvY%qX33C)TQHMRC0Ro+{bwO7wCpAQJ~yIxTE1=9_t(xo#~@RL4uI zqUGEK6veBGBY!$CV|P;Tv%Q<9?atl;w_S1vseEhZl_x5r6|M3+L=!QWu`C2@S5q8! z=jzg`Sfvwx74Z(ys;bgh)kD$FF-F<*EK7OMEUM!=4qV?Izt@Qs7Q0*ILZvPFD?C&k|iB0QlU%skXMNG9qN-J)Nxu@fU6;i@japV%4(($2G zB4X&~+D&GnW;R_NrB<}cQCh?&xzq=2&}G(7R7Fo-CprI4jz=W z^3{m_8%v$SVEN=aE4H1inuvCZrK$|}eTIm8tKvLcP*7xB`25sXURf2F2|N{mwj((q zZ+*ZKDC>lj)~wHei}dVq5{PYqey2FPt)jXx(#q0mS{M{XD`ba|%JZfT*OqVbG^M&U zUg5a2UFuZc9e;qW;<%G~;A}AVWUQ#BI`(_!w&jxekn$%h5EHR#$5`BwTWV-u6uF=d z6yW)F>!Ol)q(MPhX@@JX;Qtr3j^r0c@)Pk0@vqj0Rk1|8tV`-iW9La_btjJB)FZ!o ovj(ukQ)E;n;QdOw_w1%Zs7uV*QH~J?L7M~`S1Hv3%_#fAQ(D?Z&q%Ptu1 zmdh@vhxIhCF@R{h@w@lrvRf^?Aq%rKukpG|FAyGlY0y?W?SXAfcZ&?TMbhv2IOL{mS^0kgUG=3W95NNSWU8KiA(?lEzcOmbP$<1@?E(s;0G=#3Gks$%QL>_ z{6Q4jzAICdrlqyFKzgInWRrYK@F79z7s(apsJ< zw44jenC=mIYF92a#>QF`<7Ki}9yGqAsJ!o8Al zeK;4-)ePeSe=dw;kQ%i8ZI9P=Rz{|tFY4oTb)>I4;?IExAT{H)6E3f-zBF$>Zk{N; zJ0FJ8g}ovlT45`#&}gC;hyq-*coDHJfctfi2*CGr4X-GG^YA?Fe5155O9bEoygoe=fYmAobLqQJG#>OS$cA z{I0HTuX9K(ov|g$>pEL*I|oOoZMN&>!U`9pcD=X?ysmTPwsUd4+GaD&h6a%Oc5+{@ z>s)Cj1CJ^*jUzMVK_f`LwJXKE9z$9wPqe~SgQwCZn}CpE(FEFH8?CL8>CXWVr1tC& zc-^f`o`slFJe{H~XOQ}G$$<>7t59-14^R9e!=fonH*vcuw8M5uMvpwZ+*g z!VjAf-VVpFmTGasdxUqnN-dtY?acUYkFykI+d4T=2&u1Te89Y}_8FOaf#`ta#*8I< zYjC~p5zXPprqb*hbifW;N27CLmS_$a;YC`BvA3xn5FPQ!U&c@v>u{ox?h!5El?F0c zb+{NW)=G>o8x>}W7H|n(qLmo$q7LFB95Z4p9cc+uiF%f3376ufT8Z&z6CFee?w=@^ z&xX~_B&oCEGQ3PHG3GSWL0pUrr%j>L=fGM@npxr;_!s_5yWDue<x7-%-D*#L@EZvrMOy|ZV;I+53YyQfP=fa*K=tBK~cWA3@6p4I}WL>tLu5) ztuB*R`4_Gt3wuO{Nhl{BPOg7R<6e$mC^Amt#v%3iN6)&wuFEBvD{%CIIds8uVS))k z=fV|uh1SWa(F39relun+tr~EM5^qB|WP+IiSK^ggC*vUV=PBc7T+vB_5Qr;rs#3#G zrW*1g_2SraujfjM{~)fy6G{!^O*J%w)R7;aVqVWxQVk%k#uM*ZPWCv(o?VMv?a9dW z159C%dTYej9ugB%e{~7-x^9$g zyWp$pj>m{?E@VS$>eP$8o-WoEZ^F0Lj$dg<9%zu7zHSopdTx?i^2E)!#$=TNw*&KM zLjk0A9_i(E-7FofE3Pt^9i@yv8*(9aY$*km>V|U_ zDd(kHKx)q6+05(eCU7{9hI)`1f3(o+>YkCQ2gI#7@0bMAZ^xZK%jH7&-drw(tMO{Blkpub z-+|j6mw^H>pB%=o!nNLQx8GqEe=WtGcq`qq;|&4|6G~E`W);?h!>WTbJl} z9$bUhXdR753bVxda4lY|bu{KsfqMa5hu3K(#7?9t`3xe1(+mK#;V)?~?ky8>i9+3MZ#kiXb)Ng>B61 zx?8pc_u#%mR%LRRtgPBWYUB3bnb&oXbj5pdk#e+O%=B>|o>1xIquS}?-uozhhdLFRRpW@P&FpfRL=e0wnSdhV6h%M!f9s zF0Kk`wq7{NR7nQ4ApUHq52-_k94e7m2yI0{sr!QrL8&WS1Kg;W? zk_M{A37F7cjX|{7{w%A>6B?>>lZOR!#1DNIG6WocE7+?k83EFz%i9B;C0!47osFwk_O(w`e8C@8|0v z9>L$H$mMqM{rPga9dyHPT8Z&3EkBCmUXt+M9(Lu+<@V4WyK5!J$N4&l|KKxw<#G#H z-bnU>)*Uh*e&o^rP?44=9>aGjipaEPT009;Uwm|z*Y%jR$$xS0X6a-d;1!SV5f{R6 z)0sNJt$3@}#hC7KxXypmuHzFahC`KC$T>i+icC+6kz0W1&+r?k3Uicv?*1$zQ}>Ah z48NpKUG?bxTonVJ0gNhufEdW|FkQeSJTTVwtsJ${J&;Hhh(Qd0HhFb~YI$9A*3c1d z!`rkRqspJ7e8)YAj`+l2hOhRc_Zq1B54b+@<#+Ug$B9=4I8yy9Z`H~w3@%Lo*D#U*ez-mTqf zwDF&%G~gY~hOnVb8p$VyF?@c~RC1F`VUgLHT?+T$J=(p-ENa|_Gd#3yB=Ne;nkQWb z_u+k7sd0<$6OS`oy=5Ss{uh;rlsx|h_v8KAoyK^k`@|Cr=Ps9iaye`$kn5L22t!(l zaUx&$i4hFfy(8DJfHwnj{R-%TJ+ueAif8Yq)ou7;l2Q!6p1xC*`E8mPbut(Q@%`@~p=hx(5rj@QEXCQ@Gul~}3uG8R*T z@+8B<`(^EM9b6|ZcO5){4`{uNYjvM^is9BR)9G|)IA)&i485_pc7yRX(@~6L__<04 zyQpT#kmgtWV1!iJSoetu3`g&jrf31bGz8`c#WQm}o4_cfePSZR zP4CM#?nYQZgUKv$BSbN(l^F9{>L?~L+`GX7+JQFE>L8wGxMl53@}q3%4$O~=dfr4f zi9OBi*&T?<3};bImbf1{daNXxJ5WC6Fv(PKLK@HYuHyAZ~ zfmpzB=1;QN?hbcJE^+CH-JuWm(QYtq@t*}bkoxfCr39z**nGBt_=0$W;q=WGaCZQv zHxUaNe)F=7NGDid4kHSHTyzn`9Rp=V-3qgtNI`FfzSvhQF`jOs`@~{~2i06k%P~IZ4wbzsRTdD-8E&Ryr|8xy%sk8GMxS_% z;kTQl{4N+s(PBr`YbLVPS7K)+o@VKRGK$w3jyNpwSFhDj+fn|y1OgB%7>*k@n4t6y zpu)~8?tq8!VeJtkM+dQz;o==jY4uKMC7t$8coZMi{$mizzrk?M$(QKj|AtNG#s3YD z;bYo=jR{=$i8mPznkLupg3VNz#W2OR{>)gP;rA)`6D!zC_6B>C=>_5~hND%~ zI)|>7r@G%F1EE;O@Mo%9JmPNnDo2(qJE>&J5qHA?h69*ZV(iLssBD#4rJ#75;b%Ws zE<3T7%UV8=`L^Y<1>zlsW9t$IA+>yY-0Oaagz<@Y8Ln1k_z4rVEMsQ8%OvKbSk3VG z&z4R0*mF>aO;$^r1jHJKv+Il#i>7;x$@M*k&na9Q*+I4ymXgGK7K%73wd!<2(tYB6 zhVT3)g}Dcwr)-`h?ty^}2a?)mka0g?IB195(E>iNoxodNgJ8j;rYZShCdvUo0`HdLIIoBCU(AAV(0~8GsA_-Q=Nk!s~LB1CINloQ-Of@u||rXAFNEZ_NY>fuK)q`OGYnKzz>dICb2VGpPcz74f;r=L?1}5=7Gw zVh|M=cBk_N?Evv5!)Y{^af^I-L~^l2&G^#f;uBjKzDb#xh|na%;Q(7qB3l{$szfy; z5zBBHTTLP$wlQ3&`21IHQT4<&b4x&MXE^4F1X@pR>st4AZ#TK^V7Pdz>|gGKtAQ0} zi~C?O!@*1|H7?VAVkg7*w#g2rR8ABNb3`c&VK{_ocN))7O}>laeuY|lY}C?yVmHHy zQ)KSGANDi@I(t71WjK@~^8IEyiaiXMtQb#l8-l~lbdTr(i|CD8jtIdphQny%&&>*R zMGqLxa5&Q*XU01e>|Zf_ZMtk+%HRjLBwYqiFnoe(mm6=n{SB1TU>MuMcCuaUKNsz0 zd)QYb*VhccH5=FTI}6KB?ypHJKJg91d6dtn`<3HwJJP?Aksc7=GJK}a@KL0`B~k(L z9m9zP8mFX2YoF&kNzf<0XZZ1-@=EpK)7ozQy$QGh@dLwECJwIv&{HY<4@&0`%Nl8GMs0AzTl@1 z7aXzvBQrlV0C9lf7pmgBLRNeS8LoW$l#1^PSQG%}0QUpzpbfo;7|#3~gB&9LIZ{q5 z2@4>8Vz@|kNx8Lxh=FYurNpTf-wxo(61BP=st0h;nE%QTqP_s4^+Zf zhGS{RQrht+!`0-i9&rUMCJ)V5ytDscC)uCMN1KWi$NpxG^Uv;+;&Q^)pW}{Cq@vou zd~yyu3HIl9LLIt6lI8;4LyT9Sypy@hp@Jh=CmUnJDLh(M+bb+O5ez zk|Q7naePzlb4>H?>wxJlpamV1f1nCdJ4hkZGk!Bh5 z06fX?Nh)KuQ}tjWQoSpNaO=gCPYmU_?Wk24$Y$Dpr8JbEugZsE98aoOvLmT{uvIdQ z(|pq>hI4#UrJkM5fcYD!6zM4JhI1<+JkIfV%BLQYFW)}<^OSTMk8?Ri@rfrm?)+SO zN^dw2l&;kqo?`eEdCH!k?h_+8PWn>rsDeSJFIB-fhT~|*Z?t11$CcZx0(2x5pti}M z;3N1*ZcdR#aUAll#346*;zD(%rDV@2c|R1RIZiwxDe3TCot5`!i`W>BhZHO5jfWqn| z+XTcUj&D=qIwk!pi%#MJ8N^mOkadC`ag@_fbKI@o!+%XhfjwP%nhxp#F`46jRTIo} z#~>Np*#D-!WPRWGxFf#?#B7d-&2GWte0^uvd$Wn4Pt4)CU5$30A~&()Y!0^u zm2){xp|70i`=$dlDYN&?8m& zQ^=WK4mxVkh1?v=2gD+dqs+|g9G5xNxQN6+v6$lz>m&|d08i+8x_0p^1J+y2Rpo+W z3CFih?@Pd!l<;Eas5D0;U@F6@OzUWT!Tk-DQhZCK$2sxTCtl>ZpYVY?jqk~Fb}oBS z2Dncw<@l2NBz!)BsNGU8wQ6+~FLB)X&t3XU>7oL~%N)1WaZw$_GLAFXTJIsQt`#pY z^JUzA3*i&5aGXEM>h9ieCWp1Ja$NYLH6W2_Wryu6d=Gooy3lfthu2Frw}DAi`Pk`Z zd98Hg6R&Z6R;kBo#H?8Iyhhage&wL`I&`%2&g&ePsrPOZ37PGp?R8Eshpd@SK&;@n zSGmSpP7hU{yn@JtXI}n&j(Z54 z9qo@&_xrR1#RnY6?viy}5~P3Ez`i!X3UfsgrZJqxv}c$xh8O0D8hDoBvjjX}QLFGF z$CF9}AJXe3TLT~P4^PzqinScqn)qG}+nJQ|ri?Pwp!*FB;y450T&*`g0jXE>d}uYO^U=nKy=e2!G~dwU(kCmfe=o=#0}H+Zbp z++hR%#4JZaY~(md%}D9X2s_<6;&YBG393%1^sMOfd`^I+7l8&?91Y^NU*Np{(|WF#Frdb9Ci$X9bkIfmwdfB+4PAm9QXgFLbM2Zwn&Bnv6bT} zYGK{tAvjw$vNPygf^6{+%wRZ!Ox4oit6TZVx?YBE6t5pV&+vJs&16Qtmu85)j4L9Dg$T)_T$A7&LxO>>a+}s#JcbtLU^U${^VL zhT|V~DnxnbH^k2;zU8>`Z}Qi-Du4OJchn=um-zKy0O72S^WT~MnooSsam|m?FVBVH zWL>)o{+_E|-r*bxXTcK?KX5!;r@-oBKajuyv6th~f84j1_W8sgw<8?iogw2t5B88r?1J?OH~&D$Cw}3$ zYpZOxm>du}3aVeYRo42%QI1nb%MY0T1Ct0La>ajO9>aM|o6n5J^bON7j*rifRm5Yk zk0uAX;xSmjZ~@a^V1^v{ALsb-RO_wnCTeSJw?4{`@#9HMkE#%Vfuh5{*NL>m|KoT}wPItbptlMA&oomr@f*iqev;Fh|H6xPwa5R3g$x&x zLoKBC*m4NZZaR?pHxPqe z_yv_I8KOUfSrm_LU>bdTn@0~8GhEE5+MLB5Xf@bX8&QY2aLqraoFOhba31Qya(VI5h+27*Is`oS?X z_BX@S?!{wg>~E%}Rte)pT5>@uwT2#HD)j;V)KV#CETttkq*kq?N0^$vfqrVKRm^ya zHALZo)T+=z3siYlVP^D8RrCTA4J!=dtUyj4-RaHzb9Xtxe_DLz%|ifD1H zcSUh^w7l3MTJ!QyGSs}>67KRot&7?fwUdIDCXyr)-Q^s|fm(N|%{-Xjqo!wNw8$vz zUKWZ(NGAG6Fj$8)r|M9iEl!k$BE<4y2g@GOXjS{R#j$v_f>c#pR$X3P7D~qC|44=! zlNp`8rm`v=yr>R_eZrx5O)?t$8#2YASd93#|3C083nhbXPWxP!P-R4#sjcm8)#2*u zXrFNKk~#!GRa45_tW%|->hkt&ixR=+YN0Zc496p(s^UbyL|Le+s;Im9vwiU9Gh*;p zI>n(xb!k;)q~@VC&$ASZZlS(uE;s%E<6@CCIgwHFtS9Oo!Annzfptp#wCQDAD@7DK z!K==Q*u&OYlbWT6il|MK!tgW=X^~PtOKT#P^1e;dijPIBs){NrBGGtdq~hw%H{IH; z^UbGu`&u-LdzPoEW381Uqwt!mOz;TiMHBREWmUM9shW1DrJ87>xMyWmxHJ|`nDRU6 zNOcsS2_4dA>%R}DBBSt1Lhs5*1<@vyp`XDE>)>%}&?^ujCYSy_lT$Dzkt7RTQyGyA zBjJaVb=vq;hPA+|I1vuT%X$&>93u5lkABH;k7#+n;I(x~e`@5XEl1}I>D^4A7w z!KA~QE@du(!>7!%&L`%c`WA2%g%bTDWnJUpaCNM1{hq24>u7PzJeAhNS=K^PSw-~9 zUg5IdSHvrVfxkZN8kLd<&$bq94TqA^>dLYrqp))%*}iS7q8p>3^5E5{rOUseRh&-d zwrnKWt(Dc`cp}*LjA+N=(K0fW&tg`TNQOgIcSPg8ZEg0fjFfk)i9|v@s=`4?Z!GH- zF0ZKy2XobvSSa4Rv^tohey^sS5$t$I@=#__d8nDxDdiu_8+w*^sY!+(YE=~PTNN$q z9lY$cNY|o509H*z=+b||N7LP;bKOYfo7Xy7WH|ZPM5F{w|GI@Rkg~yT=K4SQ!)=w3 zWJk*%T3RZzWlg(Hr)adw+ErlfDvF20l$otivJF-HDaAmMQD~{m66o}5C^}l4R#U#> zTN$}79E#l>@16{m^*&8dx6T$<_X>w(Wt6@}Sw*yS;@YSRopelvAF51RSL+!{ByBHu zEZ9!gw=y1%*V>;CU%Aq9kpnZtbU7AQ6!oSTh!9BHTI{pg1bB_?C80uLMypq+`qKd+;G#<8Ms65y(jc%0ILsb=yav*KCnnYFD8G-Sd z$b%K}P!Btl=!r}#ROLr(g_K9T$0{Sig4)U;|CXxo*M2S`ISobea3Y*c#400^%1A{J zPl@JGd7n_EEF8=>SIXnj*p=OE?N*0kp|Y}YBGI~(F5SNE8HROrC}tfb9XGRdSsaVS zqdkj^Li*7q6l+yf6^-_;iPhOiCdzvkS48XT{v{P+L9`3&qFq@P?o?A*C2Pn~dHI!H zZ=-fPc<~uQlgTC)k0ztUs8MZ3bcM>Quq>?N|2N7+f+(kvuw|h{MIsqW);PeFK*P*at%HrFms=zWBdisfwr$F>E}=y4qC_}p zOC75$uL@U$lR>mjr=L(*$+&2o4q&T-BApW4$zV#KtBI9|k`iR%U5U?Mc*JUwY40d9 z3KQY#Td5RmRTPg#lh;J!wndG?YRa#zih6_+;b220mr)oGMarYqS4V29TbWId3Yj9K zkdW%S%0x0+5f4>U!&nxLm!DzC^it=^98DEpRkGg}=^csoji^c^?MS9lNgw}Tg&I}v zSCp6AMT${aQBxU7#**HZ#C zO)8}Jbh&Awb*Gx1^MbO9Xz;A!s>&Yi+tUBbE(jL2 z2^J-yL8M>Jhw*SCTGc1L(!gGcC3{iyq?deZ$$pe^cc1b^^xmNN?mmfriLy{t)xH03 Q00030|CiUL!{Af^06t(YmH+?% From 62d258be8f6d112ce1379c399c25b44a2851a2ee Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sat, 23 Dec 2023 21:26:56 +0100 Subject: [PATCH 12/36] Revert "Use Boyer-Moore strings finder" This reverts commit 7ee8679ab9501e31f718a4c01f7df05ad8af1ac1. --- cmd/catp/catp/app.go | 10 +-- cmd/catp/catp/search.go | 122 ----------------------------------- cmd/catp/catp/search_test.go | 41 ------------ 3 files changed, 5 insertions(+), 168 deletions(-) delete mode 100644 cmd/catp/catp/search.go delete mode 100644 cmd/catp/catp/search_test.go diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index 770ec5b..aa4ec92 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -3,6 +3,7 @@ package catp import ( "bufio" + "bytes" "flag" "fmt" "io" @@ -34,7 +35,7 @@ type runner struct { currentLines int64 // grep is a slice of AND items, that are slices of OR items. - grep [][]*stringFinder + grep [][][]byte currentFile *progress.CountingReader currentTotal int64 @@ -90,7 +91,7 @@ func (r *runner) scanFile(rd io.Reader) { for _, andGrep := range r.grep { andPassed := false for _, orGrep := range andGrep { - if orGrep.next(s.Bytes()) != -1 { + if bytes.Contains(s.Bytes(), orGrep) { andPassed = true break @@ -298,10 +299,9 @@ func Main() error { //nolint:funlen,cyclop if len(grep) > 0 { for _, andGrep := range grep { - var og []*stringFinder + var og [][]byte for _, orGrep := range strings.Split(andGrep, "\\|") { - sf := makeStringFinder(orGrep) - og = append(og, sf) + og = append(og, []byte(orGrep)) } r.grep = append(r.grep, og) diff --git a/cmd/catp/catp/search.go b/cmd/catp/catp/search.go deleted file mode 100644 index ece593e..0000000 --- a/cmd/catp/catp/search.go +++ /dev/null @@ -1,122 +0,0 @@ -// This file is a []byte conversion of https://raw.githubusercontent.com/golang/go/master/src/strings/search.go. - -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package catp - -import "strings" - -// stringFinder efficiently finds strings in a source text. It's implemented -// using the Boyer-Moore string search algorithm: -// https://en.wikipedia.org/wiki/Boyer-Moore_string_search_algorithm -// https://www.cs.utexas.edu/~moore/publications/fstrpos.pdf (note: this aged -// document uses 1-based indexing) -type stringFinder struct { - // pattern is the string that we are searching for in the text. - pattern string - - // badCharSkip[b] contains the distance between the last byte of pattern - // and the rightmost occurrence of b in pattern. If b is not in pattern, - // badCharSkip[b] is len(pattern). - // - // Whenever a mismatch is found with byte b in the text, we can safely - // shift the matching frame at least badCharSkip[b] until the next time - // the matching char could be in alignment. - badCharSkip [256]int - - // goodSuffixSkip[i] defines how far we can shift the matching frame given - // that the suffix pattern[i+1:] matches, but the byte pattern[i] does - // not. There are two cases to consider: - // - // 1. The matched suffix occurs elsewhere in pattern (with a different - // byte preceding it that we might possibly match). In this case, we can - // shift the matching frame to align with the next suffix chunk. For - // example, the pattern "mississi" has the suffix "issi" next occurring - // (in right-to-left order) at index 1, so goodSuffixSkip[3] == - // shift+len(suffix) == 3+4 == 7. - // - // 2. If the matched suffix does not occur elsewhere in pattern, then the - // matching frame may share part of its prefix with the end of the - // matching suffix. In this case, goodSuffixSkip[i] will contain how far - // to shift the frame to align this portion of the prefix to the - // suffix. For example, in the pattern "abcxxxabc", when the first - // mismatch from the back is found to be in position 3, the matching - // suffix "xxabc" is not found elsewhere in the pattern. However, its - // rightmost "abc" (at position 6) is a prefix of the whole pattern, so - // goodSuffixSkip[3] == shift+len(suffix) == 6+5 == 11. - goodSuffixSkip []int -} - -func makeStringFinder(pattern string) *stringFinder { - f := &stringFinder{ - pattern: pattern, - goodSuffixSkip: make([]int, len(pattern)), - } - // last is the index of the last character in the pattern. - last := len(pattern) - 1 - - // Build bad character table. - // Bytes not in the pattern can skip one pattern's length. - for i := range f.badCharSkip { - f.badCharSkip[i] = len(pattern) - } - // The loop condition is < instead of <= so that the last byte does not - // have a zero distance to itself. Finding this byte out of place implies - // that it is not in the last position. - for i := 0; i < last; i++ { - f.badCharSkip[pattern[i]] = last - i - } - - // Build good suffix table. - // First pass: set each value to the next index which starts a prefix of - // pattern. - lastPrefix := last - for i := last; i >= 0; i-- { - if strings.HasPrefix(pattern, pattern[i+1:]) { - lastPrefix = i + 1 - } - // lastPrefix is the shift, and (last-i) is len(suffix). - f.goodSuffixSkip[i] = lastPrefix + last - i - } - // Second pass: find repeats of pattern's suffix starting from the front. - for i := 0; i < last; i++ { - lenSuffix := longestCommonSuffix(pattern, pattern[1:i+1]) - if pattern[i-lenSuffix] != pattern[last-lenSuffix] { - // (last-i) is the shift, and lenSuffix is len(suffix). - f.goodSuffixSkip[last-lenSuffix] = lenSuffix + last - i - } - } - - return f -} - -func longestCommonSuffix(a, b string) (i int) { - for ; i < len(a) && i < len(b); i++ { - if a[len(a)-1-i] != b[len(b)-1-i] { - break - } - } - return -} - -// next returns the index in text of the first occurrence of the pattern. If -// the pattern is not found, it returns -1. -func (f *stringFinder) next(text []byte) int { - i := len(f.pattern) - 1 - for i < len(text) { - // Compare backwards from the end until the first unmatching character. - j := len(f.pattern) - 1 - for j >= 0 && text[i] == f.pattern[j] { - i-- - j-- - } - if j < 0 { - return i + 1 // match - } - - i += max(f.badCharSkip[text[i]], f.goodSuffixSkip[j]) - } - return -1 -} diff --git a/cmd/catp/catp/search_test.go b/cmd/catp/catp/search_test.go deleted file mode 100644 index 8d8cd20..0000000 --- a/cmd/catp/catp/search_test.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package catp - -import ( - "testing" -) - -func TestFinderNext(t *testing.T) { - testCases := []struct { - pat, text string - index int - }{ - {"", "", 0}, - {"", "abc", 0}, - {"abc", "", -1}, - {"abc", "abc", 0}, - {"d", "abcdefg", 3}, - {"nan", "banana", 2}, - {"pan", "anpanman", 2}, - {"nnaaman", "anpanmanam", -1}, - {"abcd", "abc", -1}, - {"abcd", "bcd", -1}, - {"bcd", "abcd", 1}, - {"abc", "acca", -1}, - {"aa", "aaa", 0}, - {"baa", "aaaaa", -1}, - {"at that", "which finally halts. at that point", 22}, - } - - for _, tc := range testCases { - sf := makeStringFinder(tc.pat) - got := sf.next([]byte(tc.text)) - want := tc.index - if got != want { - t.Errorf("stringFind(%q, %q) got %d, want %d\n", tc.pat, tc.text, got, want) - } - } -} From 17405573234a983d3040eb3ce7b784e1e3d677e0 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sat, 23 Dec 2023 22:01:01 +0100 Subject: [PATCH 13/36] Fix lint --- .golangci.yml | 2 + cmd/catp/catp/app.go | 95 +++++++++++++++++++------------- cmd/catp/catp/zstd.go | 6 +- progress.go | 124 +++++++++++++++++++----------------------- 4 files changed, 118 insertions(+), 109 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index a035208..6b00dce 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -16,6 +16,8 @@ linters-settings: check-exported: false unparam: check-exported: true + funlen: + lines: 70 linters: enable-all: true diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index aa4ec92..6ab8f46 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -79,8 +79,8 @@ func (r *runner) scanFile(rd io.Reader) { s.Buffer(make([]byte, 64*1024), 10*1024*1024) lines := 0 + for s.Scan() { - shouldWrite := true lines++ if lines >= 1000 { @@ -88,24 +88,7 @@ func (r *runner) scanFile(rd io.Reader) { lines = 0 } - for _, andGrep := range r.grep { - andPassed := false - for _, orGrep := range andGrep { - if bytes.Contains(s.Bytes(), orGrep) { - andPassed = true - - break - } - } - - if !andPassed { - shouldWrite = false - - break - } - } - - if !shouldWrite { + if !r.shouldWrite(s.Bytes()) { continue } @@ -140,6 +123,30 @@ func (r *runner) scanFile(rd io.Reader) { } } +func (r *runner) shouldWrite(line []byte) bool { + shouldWrite := true + + for _, andGrep := range r.grep { + andPassed := false + + for _, orGrep := range andGrep { + if bytes.Contains(line, orGrep) { + andPassed = true + + break + } + } + + if !andPassed { + shouldWrite = false + + break + } + } + + return shouldWrite +} + func (r *runner) cat(filename string) (err error) { file, err := os.Open(filename) //nolint:gosec if err != nil { @@ -152,7 +159,9 @@ func (r *runner) cat(filename string) (err error) { } }() - cr := progress.NewSharedCountingReader(file, &r.currentBytes, nil) + cr := progress.NewCountingReader(file) + cr.SetBytes(&r.currentBytes) + cr.SetLines(nil) if r.parallel <= 1 { cr = progress.NewCountingReader(file) @@ -163,21 +172,8 @@ func (r *runner) cat(filename string) (err error) { rd := io.Reader(cr) - switch { - case strings.HasSuffix(filename, ".gz"): - if rd, err = gzip.NewReader(rd); err != nil { - return fmt.Errorf("failed to init gzip reader: %w", err) - } - case strings.HasSuffix(filename, ".zst"): - if r.parallel >= 1 { - if rd, err = zstdReader(rd); err != nil { - return fmt.Errorf("failed to init zst reader: %w", err) - } - } else { - if rd, err = zstd.NewReader(rd); err != nil { - return fmt.Errorf("failed to init zst reader: %w", err) - } - } + if rd, err = r.openReader(rd, filename); err != nil { + return err } if r.parallel <= 1 { @@ -199,7 +195,7 @@ func (r *runner) cat(filename string) (err error) { r.readFile(rd) } - cr.Sync() + cr.Close() if r.parallel <= 1 { r.pr.Stop() @@ -208,6 +204,29 @@ func (r *runner) cat(filename string) (err error) { return r.lastErr } +func (r *runner) openReader(rd io.Reader, filename string) (io.Reader, error) { + var err error + + switch { + case strings.HasSuffix(filename, ".gz"): + if rd, err = gzip.NewReader(rd); err != nil { + return nil, fmt.Errorf("failed to init gzip reader: %w", err) + } + case strings.HasSuffix(filename, ".zst"): + if r.parallel >= 1 { + if rd, err = zstdReader(rd); err != nil { + return nil, fmt.Errorf("failed to init zst reader: %w", err) + } + } else { + if rd, err = zstd.NewReader(rd); err != nil { + return nil, fmt.Errorf("failed to init zst reader: %w", err) + } + } + } + + return rd, nil +} + func startProfiling(cpuProfile string, memProfile string) { f, err := os.Create(cpuProfile) //nolint:gosec if err != nil { @@ -246,16 +265,18 @@ func (i *stringFlags) String() string { func (i *stringFlags) Set(value string) error { *i = append(*i, value) + return nil } // Main is the entry point for catp CLI tool. -func Main() error { //nolint:funlen,cyclop +func Main() error { //nolint:funlen,cyclop,gocognit var grep stringFlags flag.Var(&grep, "grep", "grep pattern, may contain multiple OR patterns separated by \\|,\n"+ "each -grep value is added with AND logic, akin to extra '| grep foo',\n"+ "for example, you can use '-grep bar\\|baz -grep foo' to only keep lines that have (bar OR baz) AND foo") + parallel := flag.Int("parallel", 0, "number of parallel readers if multiple files are provided") cpuProfile := flag.String("dbg-cpu-prof", "", "write first 10 seconds of CPU profile to file") memProfile := flag.String("dbg-mem-prof", "", "write heap profile to file after 10 seconds") diff --git a/cmd/catp/catp/zstd.go b/cmd/catp/catp/zstd.go index 007bf79..472f7d3 100644 --- a/cmd/catp/catp/zstd.go +++ b/cmd/catp/catp/zstd.go @@ -10,9 +10,9 @@ import ( ) func zstdReader(rd io.Reader) (io.Reader, error) { - if rd, err := zstd.NewReader(rd, zstd.WithDecoderConcurrency(1)); err != nil { - return nil, fmt.Errorf("failed to init zst reader: %w", err) - } else { + if rd, err := zstd.NewReader(rd, zstd.WithDecoderConcurrency(1)); err == nil { return rd, nil + } else { //nolint:revive + return nil, fmt.Errorf("failed to init zst reader: %w", err) } } diff --git a/progress.go b/progress.go index 497b46d..5111fb7 100644 --- a/progress.go +++ b/progress.go @@ -232,130 +232,116 @@ func (p *Progress) Lines() int64 { return p.continuedLines } +// NewCountingReader wraps an io.Reader with counters of bytes and lines. func NewCountingReader(r io.Reader) *CountingReader { - return &CountingReader{ - Reader: r, - lines: new(int64), - readBytes: new(int64), + cr := &CountingReader{ + Reader: r, } -} + cr.lines = new(int64) + cr.bytes = new(int64) -func NewSharedCountingReader(r io.Reader, readBytes, lines *int64) *CountingReader { - return &CountingReader{ - Reader: r, - lines: lines, - readBytes: readBytes, - } + return cr } // CountingReader wraps io.Reader to count bytes. type CountingReader struct { Reader io.Reader + sharedCounters +} - lines *int64 - readBytes *int64 +type sharedCounters struct { + lines *int64 + bytes *int64 - readLocal int64 + localBytes int64 + localLines int64 } -func (cr *CountingReader) SetLines(lines *int64) { +func (cr *sharedCounters) SetLines(lines *int64) { cr.lines = lines } -func (cr *CountingReader) SetReadBytes(readBytes *int64) { - cr.readBytes = readBytes +func (cr *sharedCounters) SetBytes(bytes *int64) { + cr.bytes = bytes } -// Read reads and counts bytes. -func (cr *CountingReader) Read(p []byte) (n int, err error) { - n, err = cr.Reader.Read(p) - - cr.readLocal += int64(n) +func (cr *sharedCounters) count(n int, p []byte) { + cr.localBytes += int64(n) - if cr.readLocal > 100000 && cr.readBytes != nil { - atomic.AddInt64(cr.readBytes, cr.readLocal) - cr.readLocal = 0 + if cr.localBytes > 100000 && cr.bytes != nil { + atomic.AddInt64(cr.bytes, cr.localBytes) + cr.localBytes = 0 } if cr.lines == nil { - return n, err + return } for i := 0; i < n; i++ { if p[i] == '\n' { - atomic.AddInt64(cr.lines, 1) + cr.localLines++ + + if cr.localLines > 1000 { + atomic.AddInt64(cr.lines, cr.localLines) + cr.localLines = 0 + } } } +} + +// Read reads and counts bytes. +func (cr *CountingReader) Read(p []byte) (n int, err error) { + n, err = cr.Reader.Read(p) + cr.count(n, p) return n, err } -func (cr *CountingReader) Sync() { - if cr.readLocal > 0 && cr.readBytes != nil { - atomic.AddInt64(cr.readBytes, cr.readLocal) - cr.readLocal = 0 +func (cr *sharedCounters) Close() { + if cr.localBytes > 0 && cr.bytes != nil { + atomic.AddInt64(cr.bytes, cr.localBytes) + cr.localBytes = 0 + } + + if cr.localLines > 0 && cr.lines != nil { + atomic.AddInt64(cr.lines, cr.localLines) + cr.localLines = 0 } } -// Bytes returns number of read bytes. -func (cr *CountingReader) Bytes() int64 { - return atomic.LoadInt64(cr.readBytes) +// Bytes returns number of processed bytes. +func (cr *sharedCounters) Bytes() int64 { + return atomic.LoadInt64(cr.bytes) } -// Lines returns number of read lines. -func (cr *CountingReader) Lines() int64 { +// Lines returns number of processed lines. +func (cr *sharedCounters) Lines() int64 { return atomic.LoadInt64(cr.lines) } +// NewCountingWriter wraps an io.Writer with counters of bytes and lines. func NewCountingWriter(w io.Writer) *CountingWriter { - return &CountingWriter{ - Writer: w, - writtenBytes: new(int64), - lines: new(int64), - } -} + cw := &CountingWriter{Writer: w} + cw.lines = new(int64) + cw.bytes = new(int64) -func NewSharedCountingWriter(w io.Writer, writtenBytes, lines *int64) *CountingWriter { - return &CountingWriter{ - Writer: w, - writtenBytes: writtenBytes, - lines: lines, - } + return cw } // CountingWriter wraps io.Writer to count bytes. type CountingWriter struct { Writer io.Writer - - lines *int64 - writtenBytes *int64 + sharedCounters } // Write writes and counts bytes. func (cr *CountingWriter) Write(p []byte) (n int, err error) { n, err = cr.Writer.Write(p) - - atomic.AddInt64(cr.writtenBytes, int64(n)) - - for i := 0; i < n; i++ { - if p[i] == '\n' { - atomic.AddInt64(cr.lines, 1) - } - } + cr.count(n, p) return n, err } -// Bytes returns number of written bytes. -func (cr *CountingWriter) Bytes() int64 { - return atomic.LoadInt64(cr.writtenBytes) -} - -// Lines returns number of written bytes. -func (cr *CountingWriter) Lines() int64 { - return atomic.LoadInt64(cr.lines) -} - // MetricsExposer provides metric counters. type MetricsExposer interface { Metrics() []Metric From ed4700ac78e291881f057441f0b2a6500cbb1574 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sat, 23 Dec 2023 22:04:15 +0100 Subject: [PATCH 14/36] Update default.pgo --- cmd/catp/default.pgo | Bin 13654 -> 9141 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/cmd/catp/default.pgo b/cmd/catp/default.pgo index 7b30a451a1b74d581a64d626c2a4ff1b5c1797f8..27d294552386e195f9d697f216a9b9a0acde1fd7 100644 GIT binary patch literal 9141 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

I~_+W3+vqCZp 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 o Date: Sat, 23 Dec 2023 22:09:14 +0100 Subject: [PATCH 15/36] Try buffered writing --- cmd/catp/catp/app.go | 2 +- cmd/catp/default.pgo | Bin 9141 -> 8045 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index 6ab8f46..5f7fdc2 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -301,7 +301,7 @@ func Main() error { //nolint:funlen,cyclop,gocognit r := &runner{} r.parallel = *parallel - r.output = os.Stdout + r.output = bufio.NewWriter(os.Stdout) if *output != "" { out, err := os.Create(*output) diff --git a/cmd/catp/default.pgo b/cmd/catp/default.pgo index 27d294552386e195f9d697f216a9b9a0acde1fd7..731b76d649d397e03692d1e8b619ff372e36d738 100644 GIT binary patch literal 8045 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 literal 9141 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 Date: Sat, 23 Dec 2023 23:27:21 +0100 Subject: [PATCH 16/36] Add -progress-json flag --- cmd/catp/catp/app.go | 67 ++++++++++++++++++++++++++++++++++++------- cmd/catp/default.pgo | Bin 8045 -> 7662 bytes progress.go | 16 +++++------ 3 files changed, 65 insertions(+), 18 deletions(-) diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index 5f7fdc2..04803f8 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -4,6 +4,7 @@ package catp import ( "bufio" "bytes" + "encoding/json" "flag" "fmt" "io" @@ -25,7 +26,9 @@ type runner struct { mu sync.Mutex output io.Writer - pr *progress.Progress + pr *progress.Progress + progressJSON string + sizes map[string]int64 matches int64 totalBytes int64 @@ -47,10 +50,23 @@ type runner struct { func (r *runner) st(s progress.Status) string { var res string + type progressJSON struct { + progress.Status + CurrentFilePercent float64 `json:"current_file_percent,omitempty"` + Matches *int64 `json:"matches,omitempty"` + ElapsedSeconds float64 `json:"elapsed_seconds"` + RemainingSeconds float64 `json:"remaining_seconds"` + } + + pr := progressJSON{ + Status: s, + } + if len(r.sizes) > 1 && r.parallel <= 1 { - fileDonePercent := 100 * float64(r.currentFile.Bytes()) / float64(r.currentTotal) + pr.CurrentFilePercent = 100 * float64(r.currentFile.Bytes()) / float64(r.currentTotal) + res = fmt.Sprintf("all: %.1f%% bytes read, %s: %.1f%% bytes read, %d lines processed, %.1f l/s, %.1f MB/s, elapsed %s, remaining %s", - s.DonePercent, s.Task, fileDonePercent, s.LinesCompleted, s.SpeedLPS, s.SpeedMBPS, + s.DonePercent, s.Task, pr.CurrentFilePercent, s.LinesCompleted, s.SpeedLPS, s.SpeedMBPS, s.Elapsed.Round(10*time.Millisecond).String(), s.Remaining.String()) } else { res = fmt.Sprintf("%s: %.1f%% bytes read, %d lines processed, %.1f l/s, %.1f MB/s, elapsed %s, remaining %s", @@ -59,7 +75,20 @@ func (r *runner) st(s progress.Status) string { } if r.grep != nil { - res += fmt.Sprintf(", matches %d", atomic.LoadInt64(&r.matches)) + m := atomic.LoadInt64(&r.matches) + pr.Matches = &m + res += fmt.Sprintf(", matches %d", m) + } + + if r.progressJSON != "" { + pr.ElapsedSeconds = pr.Elapsed.Seconds() + pr.RemainingSeconds = pr.Remaining.Seconds() + + if j, err := json.Marshal(pr); err == nil { + if err = os.WriteFile(r.progressJSON, append(j, '\n'), 0o600); err != nil { + println("failed to write progress JSON: " + err.Error()) + } + } } return res @@ -270,18 +299,20 @@ func (i *stringFlags) Set(value string) error { } // Main is the entry point for catp CLI tool. -func Main() error { //nolint:funlen,cyclop,gocognit +func Main() error { //nolint:funlen,cyclop,gocognit,gocyclo var grep stringFlags flag.Var(&grep, "grep", "grep pattern, may contain multiple OR patterns separated by \\|,\n"+ "each -grep value is added with AND logic, akin to extra '| grep foo',\n"+ "for example, you can use '-grep bar\\|baz -grep foo' to only keep lines that have (bar OR baz) AND foo") - parallel := flag.Int("parallel", 0, "number of parallel readers if multiple files are provided") + parallel := flag.Int("parallel", 1, "number of parallel readers if multiple files are provided\n"+ + "use 0 for multi-threaded zst decoder (slightly faster at cost of more CPU)") cpuProfile := flag.String("dbg-cpu-prof", "", "write first 10 seconds of CPU profile to file") memProfile := flag.String("dbg-mem-prof", "", "write heap profile to file after 10 seconds") output := flag.String("output", "", "output to file instead of STDOUT") noProgress := flag.Bool("no-progress", false, "disable progress printing") + progressJSON := flag.String("progress-json", "", "write current progress to a file") ver := flag.Bool("version", false, "print version and exit") flag.Parse() @@ -301,21 +332,34 @@ func Main() error { //nolint:funlen,cyclop,gocognit r := &runner{} r.parallel = *parallel - r.output = bufio.NewWriter(os.Stdout) - if *output != "" { + if *output != "" { //nolint:nestif out, err := os.Create(*output) if err != nil { return fmt.Errorf("failed to create output file %s: %w", *output, err) } - r.output = out + w := bufio.NewWriterSize(out, 128*1024) + r.output = w defer func() { + if err := w.Flush(); err != nil { + log.Fatalf("failed to flush STDOUT buffer: %s", err) + } + if err := out.Close(); err != nil { log.Fatalf("failed to close output file %s: %s", *output, err) } }() + } else { + w := bufio.NewWriterSize(os.Stdout, 128*1024) + r.output = w + + defer func() { + if err := w.Flush(); err != nil { + log.Fatalf("failed to flush STDOUT buffer: %s", err) + } + }() } if len(grep) > 0 { @@ -330,14 +374,17 @@ func Main() error { //nolint:funlen,cyclop,gocognit } r.sizes = make(map[string]int64) + r.progressJSON = *progressJSON r.pr = &progress.Progress{ Interval: 5 * time.Second, Print: func(status progress.Status) { + s := r.st(status) + if *noProgress { return } - println(r.st(status)) + println(s) }, } diff --git a/cmd/catp/default.pgo b/cmd/catp/default.pgo index 731b76d649d397e03692d1e8b619ff372e36d738..f49af97d83621bb1c7e25579a93c740a30fc6c5a 100644 GIT binary patch literal 7662 zcmVBXM>Cp7howS`ah|X^&Ae-#UrtG3DDk3UwYjV{^F8O@%0+t~o&D^tExX?fxLurq=63M{a9#e*;Z2`*9WMU9G5yd^ zmkFHVm)pl{rp_5GWxy)koPmzIQE2_i1g_!cXFjA=4IV52R$0O|D8eFxTMrbNzzcBk z?hk3X0B(1QN-Mkol=rdYb?ac~ajE{f4 zPBUHH4L6!PFM$Kari+)t5aA~`w8qv(8>_mqgqMIH{YD#WTXChEmqGvoMjPuA)6dq$KUBJPUhEc1mEaExrBd@4FrNpyLVEm@8<<-! z5hQ+IiZ6e&j$Bs)hci0)$^aq#)Kg7vS1EDw@G@LVoLsyZZUyEm2Op##`0{GEUMBbe zFUM`;mk^(F_>o-Z=H<{9+Zyex&L(gV{_wtx-zx=Te*vVYtSNWve0W&#n9qQje%=aKy|6y(cMtrV zbSvQ=I0;WO%B)?Q>F2HS!P|sqby#3~c9`&0M@S#|VlH#*zE-UZi_8k%2KVn1Q3Pl! zqIfjpu}U`wsK5%Ny%q44K?$VyKi%8yYGZrPkMm}ZCpEkKd_FjQXWFtmLlBN2s(?}PjH{RaL?doa^>W1qV2|lf%i!ib^m}nZEt&>a- zKN)A(i*2BrSZo7bu#3^v>S}tpg?qN#M``MZE5)K8x?wltWNUy4ygM#jaUT_U0CwmC z69ZtOWpuYb)J@=(cyPK{MtGd?uY@C1Vx@74wUH3@6#VGkwY0mf+T9jT#Z!$Q)+e<4 zRJ?DRSZ)U^?A`4kh(V)=HG`RLcn^GU+geiWBxrBCc!jK@lOTj4<20+H(#mFe>-%ZmF{Wt-#a__k^e-)llIW!~um{wsK2 zTt@|*uR;3CK!@~aUj^K*zLep9eg?iq#DrGgI}1U9+8IRV;b-EC8KMxp5EMd-Bv_p( z@$)R)Mc$$cpJ`XPYM^J4yUYrHHcqiC{CI5kl_?`!XOlcXKL?-Ai?y=Vxz2GHQV8T% zy^{>Vxw!paQ8}GpbCGavCpZJoFuGgM6`28k9&WZP$AtHosb>qwgfsC>;}q*vs;~2L z{d`eCo#BX`@}1!`|?V}cV0lvFK6i^oknmX?a&ry}Rc^5bv&o)l8dQ_J1u5b>X zV}z}ziC;h5xL`d6z8f5M38lKhxp=N|o^{A&0`HG+E)vTp!-F;$oDApV`NnzHJ-X@P z1Mu1L+o@g)AqLFXMtQ!p+sW3s=be8+zy1Tnd@>OKsRA&~4uEpbz+&<#@Im;#qL^w^ z$RO*3g!?M^h4@!WhF{4XS!b>biJhNcgwLsJ9q+7GnHdEai3qtN{nECOTR%yN@bkg= zi~`>M&U{l{elRf)@QZQl-NGpr%+XDqpA0K)-&k+~USOPO&Cz{j8I3L`7x?)lc$*qs zKejcZ;iFWM6a@+U9KT^YI!03^OP&xdV8t(rFj2;1=8s-!^vE3 zE4WldVJL1<)p2%$Qx&8O^@Vg?(A%T5sPGJ7I)4Wo$o z`Bk`A1ui>qJH~>mY_h9yUEab~@x7YJD)=?{$O%MC=x|*_#K5n`i8OiY+ylD_^0H`g zEe(@?{yW@G&_W<~IA2JAM|}MJ_c)P+5?Njoes4!!#iv9>9{6y4QN{E>BtAQ-4Ht;( z=hxwuqr%-~xuu|ja-GPH>+xg7=b+6;=8k^7%!C_o?k+JDm%=4L&Q;^c4P-zC{{t>0 zJ6$IplKw!%eqN1RiI}X-sWjOxT-8M8;Wy$ps-1Qg=_#GB-zZ@tf?Ji^Kjf+%5o!Y; zf!`=#nPUTsl%bChJp4S0Ki;vOAn=&Zt{fBlNohxa?;!HP!$;w~1)@%ip^xyCY^C}r+F$~& z!wG82z03B4qNo!Te*Q;Xpj68lJLP!l`Xi|Zd^CRecacvnc$228>~ZD#(S#X(UXQOS zMmZU;Tvbnu{Ja5oQuEMxr8>+viUw2({jt9>!1}v$ylN0x8pk)D7s%^@T@>!@;2)=A z1D?QFR6cx11m&u>^@Jz~4{yX(HiciIbnxL71Ef{j33!}a|&#ur1ijFdk#1S z2I4@Y%=$p{l_?cn&8!A1s5A1Vw5J{G@UC{N~h*f}IO z=wk)rHvDFMhrq_gPlX0?KV#oroC^${pah;8V62?32E)O!actEtCizek-QcNxU&9%(u#3^(TCc3Y8G(W2Yb)71y6^ z7swdu*9#Z;`TyW669ib~+#zJg^ZyZG@n?K$vZPw=Y;lr#!Jh@yUvRf7067wns@aj? zFCypD3>T2s2@7r!_Z3p7!ZZ_J5Ag8}50X37Y$TnMJzR`ufLXW(T5 zBmV~YZ4CG20mW={yNwCuCNi9~K;ljhp`0|aaH6do@JS3Gv2&sjt`Utx>hGGwL<-2S zx*@Fb^T`aqw>LPF$RT<%iT3g-45w|EKqQA3DO;by2#5lFD#Mplo5?X(5l$860>7Q% z9@S_%2{R<#7T&JRn8xssBC!OCOx?n1g2Y#z>CJ z@HvVcjSp1E4m6!1NoF$qg5po7mswPGo{Z#~Lb4g)vlz}*adk`&F=?PCqPDQeAUw|KGuIt2!Gzq>CDp9?|b$H1i_Ali|Czbva<= zNX$FQNC%`26)+Isa~U4ZQ)k)yn@dUr_&kRH$2mPk99>)$Wo4?q;~*goJks zLO)-`@YUn)QGB4{Q?!WL*B)NJnBixt+a02A=gBx=F%uJ1fG=VAM&5*wh3i^EvGDSx z3^(kUt(iLS0Xw;97|vGLb$fCL%ZDVMuV?tI!t)$ot4dif zcmaQy;mdXlDTGvxuOGH`+raQA;*|HalJ(aH!OzPdVK`xvaJxsrv`l{e5kfH2%O7R9 zMS;DTO|x7cl_ZZb-1@F8fV=2C6Hp0P{@Ahky^-OkDqHN_l=j_KxNfHv^PceK7&b~e5IMTU33C(~kiZd$y+HnA6-fqRMJ z8s!(qF*KWNFA2W@f0^M=YFw!ljb3`L@MVQun;9NZN#M97%erJUxg@~<#_$&hGK zI>Wi@eyUB5nXlVzAi&>XxHqr*n!I^`L+}dlEezkH947U1d@Hrmw@AV_8GfI)(X0OQ zCINajCgmbgI`Fp`F1L>bJ>dvl@#=7I20<%Jcu%+lFEPrj1I}spEpmmIzs>ON_hnwn zH>*mmw<#}8FMo&O!~51y9)>}_nhwJd9AaE*HJixaW%%=Cadq4a{zcN;iOcZH65b1j z;!xvK>tp6?rMSA^Vec~eb|k>xWB6TO98fyECtTy@TN!@$s?7Ct7jY#lNlLfoX7c+C zr>JDfffh-xzb{w@_}>}MI$`|&E(!m^aPGuAC|i0%UsLCOV0n9SW!W1p!^@1ztE-`q_|~$;041YXfNIoLBII=JzriuXnnBmiT%U(L(^|3AB zUkoQJzo*?|m>7~X<^PKWm>u{h3=d5dCiR3vlvvKRc3Aca@df@V!)Nnb_9+nr_zs3g zm1U00!R%pXhY;MJf5z|^N+DOiw>H`G`%I7n-^p;P8X3psV8u>>6^nwO zcTTD*@9z`d_w)S>zqaR&+^YpuTl;N(-!gn%W#G5Y@mSL7-wJ*K{vU>iiJzW(xt^`& z{}99W{5ytEoFI)9+wUaX0}S6+rI*u4l|2UpA@J`RF3HU|S;YGHg2K;#V7QGm%(;svNLTj`*)|M1cRq zaARHzrSn}s*%lsQxFl~bNjm+AVA!7j%_WarS!|4KJM2d=~GjO#6r>E+`!+&p(8^`vv*bGPVO=fVwm zgYgGzo7?pA2^t=pCDzY_+wAr8pc<=od*t@<|%b*|~zG_XB#(P+7wJK@_7#jg_V&%47|f zz9RPbheZWKyZ#WvnBlgj7nmLR6b;{6Bl2(nOfE28d?1vXIv)fd(tGR@J^)7INW*PS zDyVexfl!OJ#we?#vV;$UI;=B1);rAf@~Il`ULv>@!NUxguR^6mtF$&=o1opMP1Gi7 zleH<@RE@Ieb`6h`(`oeE?ksqjnELG+-HUqpG!1vCm-w#~fpcJ*re$7uBcHC}ItBAz zJ7C_Y6e*srDUc8F85-Vy!b8jqt+2@S@|hYQ_*Q`VnXt+w&U~{p{6`LcXD7Is+81n= zCeS;;XKT1xU95lQv{2Q_Y++%5&(ZL~6B5pmgm-8-k4~t1?t9!U_T52Bcjb3#_`y4i zD4{NdKbbne2-eb&&=D4zrmlWy;^r5^AMuaI<<_m0CHx{7jiZgrtu@TyusaGgq@Oyyt1SL0RK?p`Iu;sHN!Lu z9VF+%yR`tNXn-%$aH%r+%Y2buByr2+|Nr1dKU@h zOEkP)>5$CPVTsaVsfKg%`azupmkJ$#FVpZ{HB=1G;kC^6sh2O;aN03tBFw|qcF~Djz{ro-+pSCX|FNWb_q8}lE^ezF)sYOVq}i)A+@BYE$&VZdNy|1I5j%qyQQ=*JwF6t7|p9 zccDo0V)&mNd)Eqk9m*bJbWh~atW2Z`^7}R1`~Ea)1DC)Px~cOaaJxOcUIKB98wqQL zURlD2KqEF932Q1%vJYr@#5w7jUjCqli}r~sISUTbWlVNByl^I|dg{-|1RX!)ZH3$0~pcG$3cw=phBJ>or_Wu{v%ll5W=5 zQ^XuQ7YJ!|QK{h~3SsuDR&9A$#%_a#pC1<8z8w1HgkysyE?NWp5e;9RE83m&XYmds zeuPpgz#rA{>wWUqMR_kc9+fg5({Qayfj)I*CD-QK0U$oj-~Wzqz$XNU29$l=@l>R_~%ht5TDkVcI|i(q|@o2j?zDd=@sfv zYi#)cgo~1qhQ|6>GOR}v&GA&YAlld*E{R9tiDWFAh}R^;o~Gt_s;(gxjMgTik^1`Z z>7h}HhFEAsBsw}4uc=POA`PKr&FD~VqGvE1Zi@B{C7Yt5CVN*XYVQixCc9u_=~J4ofw~A`R7Jn<9;k zv8J%6I$E2ku1%!IHO7*`+C=!&+PeJgtjeZXq$bwXJ$Pj-QWGTJJ;Rsg(YiJfY8+h~ zYDmVF|O8cBtFwRqp9k-E4DQ}1wDUA!iC^N4Y& z*oZ{UxbTH})IQ!%b@5cJDITd0(Y{E1Z79Q}I?_;6)jOCBduS;c98BE%jZ4MCy;{Us z?6UtSSCokFHkWX@{iS~*o{H4Pli_n)Y_C~3XC(4fSIV}<(cd5@Tzf!ppBz$aP)a91Y zE%FbWn+#HIBFmGowuLDxS*g$J=6Id3w|ypnjfwjDU|nrI(Nq_&9XNRCRaXwatcBL+ z@Cc2p$#Bo+zu<0F4jN#0h_EM-q_1`LvF^5O`n1T;iDYPGU45*&F_Elj5 z*w&B#bH6~^NPMQX-G;?Y>RhzxgGegTP)E)l98dKMcMo1rQxhK8A{~B(RVXuF zwviOUrdTqTN;cNT<8|@cY`l}vQL&ol`dGMJ5jIAeMprjv-P}MuDBSlqsY9Jc%`BN3 zi`FIvCofD~o)F&21~*!p=szkJ9eqJlZ8nDV`Hf!#F_@wMN{EU|4*{tFrm{i&E}oA#EO>biKUZ};GkM5N|KP|;5~Ur_nUv011l2pd+P z7#sHGJ{RDVDf47wB!1b*-NasnOX9xrR<}^>&Db16E}q2 c*NsVzOGYF0^*8+A00030|B<^_$Cg0=03eMMFaQ7m literal 8045 zcmV-zACll7iwFP!00004|D<|(oD)^{@4MBh=8~p6CjpWJbVE@r77-FDHgQ2^QBgny z(HWO%Lpn75qdVzI(k$v|*hFLzl|>O15Cjzv1r^)|cU)1&4P+D*7gR)1L zsnDSx{2qVM-F44B`}v-8Z`FnCmcH}#>gRU97jU~c1I6v)1>hRK;+MH!b-Ggger;y$ zmoB}OGrVul8bv3nYju??@M}|@2!;R)x;Xpd zcp)^yW}4er$aLT?T>Ft&ZUTQQVz~(vW3lEo{!o0yPz0HMn|r!lOet{bz*XG3XtJWK zoWpb`bmmZkC7Q=5(@S|FK5;zjd>)8EX3op+6u4EjkeHS7Cb;Uja4(tR=1l<*G_P@k4!kM8ylFe><%UNJgcWY^p-*dWJY1jycjG-@h~*-f z=@QFD&;na%EsZH;RS~}WFR|QAE;j=|`n8tE(*?SpH^a3Hgo}#dQ_JHc1&?9~U_e7- z7W4UFXLHD`d35UE+)a2>cTqFptzvvxdTSa3@?{ylY$eY5_1`2{eVwf&)Rf3SLWJA0CqWE?~fPKW~mJpIw*DR}Xwk ze2cgT+F%aPKXvX}JYF!E}|kgk7qxaz8AkJSyTXpd)tFIvE?O zHd;bw?5v$)e5MAAxE~BOv{Q`POmE3s<9i>hCKUourn@-8c%euDx?mSAXp{!s9N|MCA-Kp=A)K>7I<+E1M4ZCR}W2K@4FU6Uk+QImSg5ig|8DzeGZM*6&YUvMP ztJZBwt)P_QwuMuPQEQk%3cGo02xC|~&8X6Wx5Za?-$tu#U`_}LbPE>o_Ha6$u5~pwQ&rhz(6p>=JFUImK~z;o-1*EpvdIIx6`(SZ zP|=anEWkVAXTQxO0v(?2qpQ3Fe9=bOqC;QotC_~;KEWd10nWfPG}HK`jSjpsPWxDF z=?G7@60{xROgvLFjh9ddehRLibvtqF1WVeAJF;2bDFDK96)uVW-Zg7+r$8pP!0*zPAD5P<=;n0K};lKy<|= z5+Hsi*Oh<@nJ<0_xYe!#0{pxi&dtln4uq?lQa}ov2AQ9K-p$;qDoPu82oFf;m`_kw z0<9qP_2LO`HAG0~D}k1fdF=KIw^~d)d>-fqnLV$6MCd>Sx`&5xEwONM4mah%Q1 z7iSIT21k^8TP*wFi)1!Q&Km41u9w`$B0C)y6Hg+`P9cuQdpeN;?~Bu=EAF;j;fKs; zzm9dQeT6Ih{0w~akifEHc*v^ik)nr56V4DOoQX$CD;Mtyt%T5{^|e&(|(6 z0={DDYS)>hfQO%jnK{DK-Jn*4xEoxE7it5IZjSst%MRSxxK3vHZ;F7lez^N1p=Kc(b6GvRpM|jJ;8&D*G}O$oEVQQ{^&DX#@N@BPNpZ79fsom>Dd|?v6%>Ac9^Trh zGtVPi{JcMI+hy13j(YQb#Zo0#eVZ8L z1czWS4%X24h^99?0G3-!08J`NH}y8 zF0}=z7YG927veU_f|{1E1OPJct{mc4FBIkB;e+vBqM&NOUa+w1LLDp!{QM%EmseSv z&UFzf>*p8aQki_Koylhhx!~dg0-s{Yy#C*_-7452AAhFfM{ zikrW%6KAh8acsxCF15%;;J+oBOt!p{J5G)eGDqT`?`&o{mCqsb-5s6Xu8|hA%kZbE z0-AE>x@IyL3oaAPM&X*g2H1e<8buwW1iX;>bH=4^HDr6|a(pB2Hal*v%Sne)eg)33 zP@^G)I}q&(BKGjV;KKw}E*^$rffQl52rtq+hT8%0f1&vKO6qHT2>q>l_+N3U+*~B$ zX;+2%S3%(CSK@}eUXzi!l9Xu6ufny*pOGA;ew8)NT#awaY33_x$=QR?)l{^l{2E+C zb#NT$m+`-bgaiK@ek{2iGaLPlxV7Zv`2Gu=mwr~{AUhL6P1+7ssX5z9ScI1blLV@@9(cm=-s z(NfZ=7Z4Z+-MklEikE65j5@s~kKtQ?3Ilt?mBPT$A`^PUNF1q+FfR3ZWd0V8j#k79 zTzY_y!9&)p-Uq}O*9ulyR`h|(@G>oA%vO9Q($(r1doZuWWwO=$LXj(xDX&%vlquz7 z@##iFCo_F4h0f2b@OhbD`&8YO*Z&ZihmXU@3E&7`tzk+wka42^ zfLG%SQu{wF?d?2PtA+L+UV|%TK{OKuA-iIYCV&IDJ2v;^%;g~0qMC|7&d_J!SZRK4lA_JbrDP%sih`X#7VY^sO3;X@N4i`#BKRY94)4A#_ zM&t20X(aV%2Lz0_jGTaPllElf5hov6+Y^Y7hfl;AR%WYkMb3ORQ55PVeECz+wVT2w z(zm&Ew!5rtyGiz)goj^;w@WTp3of?V1=kh0^p5;`eDa;ebWS@RZqQZUmzt`|&wxd` zuJSYCL0weS=`adMX_p(<2a9-LxB{=xE;m-unePnv3;snjjZfPLi};!FSNyAH8Y^|( z!*9UdTkRA4AYeX_a+_R#gEhO~F5eoj2k%>CR&y?ncXbU|Y0(=I;EqN|?vWm|j#ev_#aONB_5_W@>xc#y7s_+&j zM)NX0li@+q;W)P0QC4S?Cc2m3%J4gaFe<>gl+f8@@2yN!V1UnJxJ{Oz4xB8NQU4umxnMJzDNoXWN8x7`~p@qxNj1&Jl#j=Q4cP%EO!q+~NDVjPlXTZ)5mi z#=e%@Z)KW|5QVof0hGY!G5m$bSn9}^iA=NI=bA_U4e;9;Zrx+gY`zPI~!D zzzvxfKMuRqal%Ew?_hY(SK`XKfNq%``rSc0^Z>t;;Ubc)@?xrXQi0BI*%04JD){+) zh6fwW4i2*UL>Ax+7=HYnt!YlG*%qk_NUpD>KHy=IYF@sO;a(Z=c~-#foG4r<1HOpi zJB_B}B1?(881AH8Ymo0!iMvP%-OKN0xNGlpnkLSI$LM;kh@S;l;+5J}#$!zP^2H2i z9ucs5HY~9&7te;P@oLR$%vW_UzlY)b2gG_mm~E~1gKO{_&1>9G{FgBNcAr>32j*Kh zIp@IN@Nb&e*i)c;`MnH3+$D~uMQ{rpPXkiLlDpYrb`M*^?qzhH>??t0kXf>%uUj2# zhxR^(OL9XioBVxbo%7IT@3^1goV|II;eLCEE(XbdEuudc+#YlH9lw-Mu#;?v4T4qIWIm0bd$Y)L=GJ4B} z5a16mypss!fRP2h2LwfcuV6S$*3GX@R`vv;uCNJLGMph#SYJB{rOcH!;e!l!%hbxj z9O;1v1)-O(VtC7acTj4b2S>XKqtAnD@mkF^j&#+%d^N+}uZnrIKTPQ;*84*QBbsR( z?4W!3LktgX6LWAW+}{D1&o6Z;Ud2|khnQ^Yz#nEfJ=YI*<){w}Wq?1za3K{J4TRST ze74mse8j3P;AzQ?#^BBWj(h5yj zVKXUw%(5cDA7}UtsYN-QH-e7~g#vs7!^3&IhRsslAPBvDBg5awyVR?0x1dY_hKKiv z_4DO>fb(Gtj?tpV^G$Rwe}>^h_leQ}0{GK<-*y31Vx`vK_>55PS%y2l6Z?S@s-zp8b<;VK1;3*-PwY=F*YB!f;pPv&SnUQGmb7 zaF478T~vb&427>U(RP8q#&F$TVsZ;ZNe;Qa5lFLR0 z`#_fk10bY_zqJkZp7Em`=6RXSe&Cc~%X1ogW$K}qy_)0&{X z{4Iv-ciC^kzU07khx7gcEzOD`McNqRID>MfeWVyd1 zDiruOhO0?u0@E9XKcqU_ER_TNU4|PP9aP>WNCW;J!}+-#*=D7_Cxiv~`wYLya}8H4 zwQ{{roC5q`43EmW%W;8_eZ})H!O+h?VE9IZH<^wD*$2#e^%&qEGTbFu=8SUEAs-5s z0saxg-=^%KdL1EOk<(Ru5g!2)aDq0%_<*{+ZJFyMOW}_hzD;mXbLVaKqk&_f{FvyF zf5Py`+ZtXnIdbb0M)yj7zMbLsjZLWAiD4Pv!EianS>~$qD+~wN?hwWS|CHg<*`h$Y zK}bZ~zS=DORA&E9hCj-gAm36UXGd96vgM||7JLo%0`thGqYI#Z@XY5iveOw zfPcntjyy_Ex7>D>XqI*#aeYQs0{@)hGIB4?^Hw*N1fN?3yBKbeh3^q|No?3tJ|}Uo`!V$ydo zn*-uDfAtUHX)iy-@QKgucK1F9=4&ZQnjK>8G{^TN|6#c4`&E=O-Qfn&7Y{RBF--vK zNccA$&HUoMXRwHmgo!v&8*1!izUGpj`#L|+E<#eCS`}s5lcQn?YrV*<$K3&0Ishb?wp(Wr4Dg%+i4`QgAV)dBfYE zMM8VzcPY5{4f_P}tplyH{O(fh`QMS=Ypezt;CCx{vpoMhzPrr!@4JPZ0AH-&44L+M z-MLs0digyH-XT%qhg_7nN9jj57y-US!DWp$(Itv?v3#$B@5l~mUlhnPyH}6|_UkN4S%-LK#)+eDn3!PDgOtdaLCmR?I0Tr3Aq$HxW5GW@Qk^rk<1NkxaN8|oX8 zmoHQBD2*F*NwUZ~>Dh@>xJ(hJLEy_3JS@+v!5rjXZjpHT0}4()EbbmkV5`N(wz}{E zg+?8^^;2+)9O1H`>^f9kVU_Gk1wYL5y+pC(=vqm1z#mlbX8EDyh@3inP_bsz0AHox zKFUS{qP(EHO1K*MY6VxxVb*%9Wb5x*P0|AVAqD5`v2W1xX46B0lb1iN-~#zc?=!hU zdzgaeDAuWpXbuj{?kXPW0se@BpEQbZk63E0QSjqN4O}DC0=`zk`3uFk#i3VD5Z8(z zI&w?&c|E|_Dfp~Bt+4x0sfeR-!^LCW5U1ye_X*0l5nRJz-?{S$8Ew53NC82ls8bFI)VaL zP`rGjf}4I7C$E06-35e-Pbm0Y&Z~l~J2omy*b@q&u@3x61?O1Pu9v=~c3gKnsnma1 z?2x%j!rfB}E|*}Dx0OC6%<}S03O+7xt`F0pEqkM~Ny*+z2l!?M4>oH5X0pF^bIu^M zC8J9;r!j@KZo`{ECX+dQl>RZyES0|+QK27WvbCcT|8|TL~HBJqIe{p zNX4Rwcty(ejGmN^r9y+_6|sr^C#7R%kMP(;O)NY*5*-(dSCpq?k(zL-VqCZ~(LH3E z$!Pa*Dj5xnU19Nms4`&|S-%M`W{LI3fJ8hUsfwq}ew9_}v2~+E(L_ynbRtpRyJxsI znW#+0QmJsXrXn1Tq-(>`NV+y;1e0~~cr4i^lp33;tFE{rS(T2NeZylD$7(b_7D?8n z6Sc?T6pqx^l3r*2Z$w8U@$;*yV`lIF#pY-vZT2|feM2Kv@z9vMc(kWkTotc~O(f5a zPE<@XFUVta!zfh6)3IbcQY``zsjdvyGbxYMRP^o{N|~NyT|8Y?6AMKv6VXU@wb|!{ zINQ6z_Ac_}Sq`%XM$(aiiOTSGsdPoCd;pnHe&xu^29{UEqKTSX3hl^rG8U;RpOB2y z*2a>ir#xDjD6dSUC)LJ8%5*&*J0qBkMJgx>M#Lf&!ad#1p?S2fOoVI4RfcO46=4Uj z_7#zIqjO~}tEowhkC|tk5EB^)dsjBDg1b;>NL4(RGTTea`lLurN>Ri^Bdwpk z%}Y*7;<0?fkyK52byd7>V!aa0rHB!c3H4Hj{r^d^Sz3~Wm9V$0-to1G>grHcWjv9ridPOA zJnXU&gD*Kj>vMR7$5hmF$DEar5j=lj7fWkTB1L~zRmZwmuIY6`u1TcAW2&lS<+X{F zrN5Jpa7XxL_>ecdJF4@Th7mG?1E`Z##Vd)oL<#e>JTe;g2-$W>NISb;LPn7A@xrQ9 zI#HR7)R6JfM6$x{n}=n?BDcAO$IAW0+h;!wMI))oR63HbOPM`Sid}6o5hYH|C8yZL zs8HraUY6ivYYPy8tv59HZ zE7wx#Sfu)jL~@+jLOvQ(6|Wdk7mr6qSI10{PgBvcv5LCtSk{orgm^Z%rncJour?Ws z)zqfTYqEReu?eYkBs%T{6VVnK7JJBd_1e}Xk}>hrJpH7CK!6vq`)IvIHL;r5-|HgP z=71C8RUZs$?bM>h=6bgF;50~Z%+{t&92!uUPK=KwPY|UV$P(j#EvqtNHWj*y`J$QC zJ}Q!l+5scX*2nI&Cb|AJ5Be=iM+>CKDYISu9syHEa7@L}x^!$}mr!y-bs{>>?00hh zAua?|HN=FpJq8CYq!L*>gxJ?dmr7+)Rjj&#+EF|jvh$$4A~CYIDsK8y^w0>}%8_a# zs}mDWu!qy;aJ@=C`ZLQ*=wUVrR;jU(WUN9!RxFw760*kdPPUHOh(*$gnkr&Fsw$p7 zy-R3FB2r-vIw21phgZ0M(&~5|ijWcPpGZ{O!u&Q>C>e{5Sae+ML>sKlE?hIZDqRz)Ess=JC!%A;94OGbtxZ5<>;U3C zDn2frm=L!mW|1UXX|11^tTY41Zj#j4Ag3c0<0J8C%q*5$CR8P3wOI}h_#G2TrOlR- zuHOEtcvbo&k*a2FEFz96tsLCwSr@@=WNjqwgkyV2xJIm%HrOWC?2);?b)+Vx(y>*CNqh51He+r;*T@MrNIv*~|A@r?VY;9W#XG?xI1V&N>_=YGZL*d<*hL z7Ai-@33$y?fe&rS-E!gf@j%ON(yN%7ocGTwOJ~cTf61+RY60Fhi+?iS(!SFd0iFs>j!_w92m3 vrpJ=$^-Es4lzmiq)%c23;u_O^)%et;R5Vguea-(300960mV+*D$3p-B85X4t diff --git a/progress.go b/progress.go index 5111fb7..d67957a 100644 --- a/progress.go +++ b/progress.go @@ -11,14 +11,14 @@ import ( // Status describes current progress. type Status struct { - Task string - DonePercent float64 - LinesCompleted int64 - SpeedMBPS float64 - SpeedLPS float64 - Elapsed time.Duration - Remaining time.Duration - Metrics []Metric + Task string `json:"task"` + DonePercent float64 `json:"done_percent"` + LinesCompleted int64 `json:"lines_completed"` + SpeedMBPS float64 `json:"speed_mbps"` + SpeedLPS float64 `json:"speed_lps"` + Elapsed time.Duration `json:"elapsed"` + Remaining time.Duration `json:"remaining"` + Metrics []Metric `json:"-"` } // Progress reports reading performance. From d2349382435f0f10f94c61db5346ef03ff668732 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sat, 23 Dec 2023 23:31:15 +0100 Subject: [PATCH 17/36] Add -progress-json flag --- cmd/catp/catp/app.go | 8 ++++---- progress.go | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index 04803f8..83a347f 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -54,8 +54,8 @@ func (r *runner) st(s progress.Status) string { progress.Status CurrentFilePercent float64 `json:"current_file_percent,omitempty"` Matches *int64 `json:"matches,omitempty"` - ElapsedSeconds float64 `json:"elapsed_seconds"` - RemainingSeconds float64 `json:"remaining_seconds"` + ElapsedSeconds float64 `json:"elapsed_sec"` + RemainingSeconds float64 `json:"remaining_sec"` } pr := progressJSON{ @@ -81,8 +81,8 @@ func (r *runner) st(s progress.Status) string { } if r.progressJSON != "" { - pr.ElapsedSeconds = pr.Elapsed.Seconds() - pr.RemainingSeconds = pr.Remaining.Seconds() + pr.ElapsedSeconds = pr.Elapsed.Truncate(time.Second).Seconds() + pr.RemainingSeconds = pr.Remaining.Round(time.Second).Seconds() if j, err := json.Marshal(pr); err == nil { if err = os.WriteFile(r.progressJSON, append(j, '\n'), 0o600); err != nil { diff --git a/progress.go b/progress.go index d67957a..3102044 100644 --- a/progress.go +++ b/progress.go @@ -16,8 +16,8 @@ type Status struct { LinesCompleted int64 `json:"lines_completed"` SpeedMBPS float64 `json:"speed_mbps"` SpeedLPS float64 `json:"speed_lps"` - Elapsed time.Duration `json:"elapsed"` - Remaining time.Duration `json:"remaining"` + Elapsed time.Duration `json:"-"` + Remaining time.Duration `json:"-"` Metrics []Metric `json:"-"` } From 18e467b1d8b78a65af5ea365f31687c562aa8f4b Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sat, 23 Dec 2023 23:36:26 +0100 Subject: [PATCH 18/36] Add -progress-json flag --- cmd/catp/catp/app.go | 2 ++ progress.go | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index 83a347f..9a0320d 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -215,6 +215,7 @@ func (r *runner) cat(filename string) (err error) { t.CurrentLines = func() int64 { return atomic.LoadInt64(&r.currentLines) } t.Task = filename t.Continue = true + t.PrintOnStart = true }) } @@ -407,6 +408,7 @@ func Main() error { //nolint:funlen,cyclop,gocognit,gocyclo t.CurrentBytes = func() int64 { return atomic.LoadInt64(&r.currentBytes) } t.CurrentLines = func() int64 { return atomic.LoadInt64(&r.currentLines) } t.Task = "all" + t.PrintOnStart = true }) sem := make(chan struct{}, *parallel) diff --git a/progress.go b/progress.go index 3102044..5260150 100644 --- a/progress.go +++ b/progress.go @@ -104,6 +104,7 @@ type Task struct { CurrentLines func() int64 Task string Continue bool + PrintOnStart bool } // Start spawns background progress reporter. @@ -155,6 +156,10 @@ func (p *Progress) startPrinter(interval time.Duration) { done := p.done t := time.NewTicker(interval) + if p.task.PrintOnStart { + p.printStatus(false) + } + go func() { for { select { From d014b4fbbd59df77a1cfdee22158acebda5346bd Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sat, 23 Dec 2023 23:41:04 +0100 Subject: [PATCH 19/36] Add -progress-json flag --- cmd/catp/catp/app.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index 9a0320d..ab60bc7 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -52,6 +52,8 @@ func (r *runner) st(s progress.Status) string { type progressJSON struct { progress.Status + BytesCompleted int64 `json:"bytes_completed"` + BytesTotal int64 `json:"bytes_total"` CurrentFilePercent float64 `json:"current_file_percent,omitempty"` Matches *int64 `json:"matches,omitempty"` ElapsedSeconds float64 `json:"elapsed_sec"` @@ -83,6 +85,8 @@ func (r *runner) st(s progress.Status) string { if r.progressJSON != "" { pr.ElapsedSeconds = pr.Elapsed.Truncate(time.Second).Seconds() pr.RemainingSeconds = pr.Remaining.Round(time.Second).Seconds() + pr.BytesCompleted = atomic.LoadInt64(&r.currentBytes) + pr.BytesTotal = atomic.LoadInt64(&r.totalBytes) if j, err := json.Marshal(pr); err == nil { if err = os.WriteFile(r.progressJSON, append(j, '\n'), 0o600); err != nil { From 0deeffa0dceb4f2588b039e502782dad37c7dde2 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sat, 23 Dec 2023 23:44:25 +0100 Subject: [PATCH 20/36] Add -progress-json flag --- progress.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/progress.go b/progress.go index 5260150..fc25071 100644 --- a/progress.go +++ b/progress.go @@ -200,10 +200,14 @@ func (p *Progress) printStatus(last bool) { s.SpeedMBPS = (b / s.Elapsed.Seconds()) / (1024 * 1024) s.SpeedLPS = float64(s.LinesCompleted) / s.Elapsed.Seconds() - s.Remaining = time.Duration(float64(100*s.Elapsed)/s.DonePercent) - s.Elapsed - s.Remaining = s.Remaining.Truncate(time.Second) + if s.DonePercent > 0 { + s.Remaining = time.Duration(float64(100*s.Elapsed)/s.DonePercent) - s.Elapsed + s.Remaining = s.Remaining.Truncate(time.Second) + } else { + s.Remaining = -1 + } - if s.Remaining > 100*time.Millisecond || last { + if s.Remaining > 100*time.Millisecond || s.Remaining == -1 || last { p.prnt(s) } } From 56b8e31f384a8b61fbec7dd89011d53034a69b8e Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sat, 23 Dec 2023 23:46:13 +0100 Subject: [PATCH 21/36] Add -progress-json flag --- progress.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/progress.go b/progress.go index fc25071..220eabf 100644 --- a/progress.go +++ b/progress.go @@ -204,10 +204,10 @@ func (p *Progress) printStatus(last bool) { s.Remaining = time.Duration(float64(100*s.Elapsed)/s.DonePercent) - s.Elapsed s.Remaining = s.Remaining.Truncate(time.Second) } else { - s.Remaining = -1 + s.Remaining = 0 } - if s.Remaining > 100*time.Millisecond || s.Remaining == -1 || last { + if s.Remaining > 100*time.Millisecond || s.Remaining == 0 || last { p.prnt(s) } } From 07319328f0c27b99f84e5242ffeb01f32850cc96 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sat, 23 Dec 2023 23:53:50 +0100 Subject: [PATCH 22/36] Add -progress-json flag --- progress.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/progress.go b/progress.go index 220eabf..6de875e 100644 --- a/progress.go +++ b/progress.go @@ -156,10 +156,6 @@ func (p *Progress) startPrinter(interval time.Duration) { done := p.done t := time.NewTicker(interval) - if p.task.PrintOnStart { - p.printStatus(false) - } - go func() { for { select { @@ -173,6 +169,13 @@ func (p *Progress) startPrinter(interval time.Duration) { } } }() + + if p.task.PrintOnStart { + go func() { + time.Sleep(time.Millisecond) + p.printStatus(false) + }() + } } // AddMetrics adds more metrics to progress status message. From a054ee721b3a2247509afa32431297b0461fb306 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sun, 24 Dec 2023 00:49:30 +0100 Subject: [PATCH 23/36] Add -progress-json flag --- cmd/catp/catp/app.go | 52 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index ab60bc7..45a128a 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -10,6 +10,7 @@ import ( "io" "log" "os" + "path" "runtime/pprof" "strings" "sync" @@ -32,6 +33,7 @@ type runner struct { sizes map[string]int64 matches int64 totalBytes int64 + outDir string parallel int currentBytes int64 @@ -98,16 +100,16 @@ func (r *runner) st(s progress.Status) string { return res } -func (r *runner) readFile(rd io.Reader) { +func (r *runner) readFile(rd io.Reader, out io.Writer) { b := bufio.NewReaderSize(rd, 64*1024) - _, err := io.Copy(r.output, b) + _, err := io.Copy(out, b) if err != nil { log.Fatal(err) } } -func (r *runner) scanFile(rd io.Reader) { +func (r *runner) scanFile(rd io.Reader, out io.Writer) { s := bufio.NewScanner(rd) s.Buffer(make([]byte, 64*1024), 10*1024*1024) @@ -131,7 +133,7 @@ func (r *runner) scanFile(rd io.Reader) { r.mu.Lock() } - if _, err := r.output.Write(append(s.Bytes(), '\n')); err != nil { + if _, err := out.Write(append(s.Bytes(), '\n')); err != nil { r.lastErr = err if r.parallel > 1 { @@ -180,7 +182,7 @@ func (r *runner) shouldWrite(line []byte) bool { return shouldWrite } -func (r *runner) cat(filename string) (err error) { +func (r *runner) cat(filename string) (err error) { //nolint:funlen,cyclop file, err := os.Open(filename) //nolint:gosec if err != nil { return err @@ -209,6 +211,30 @@ func (r *runner) cat(filename string) (err error) { return err } + out := r.output + + if r.outDir != "" { + fn := r.outDir + "/" + path.Base(filename) + if strings.HasSuffix(fn, ".gz") { + fn = strings.TrimSuffix(fn, ".gz") + } else { + fn = strings.TrimSuffix(fn, ".zst") + } + + w, err := os.Create(fn) //nolint:gosec + if err != nil { + return err + } + + defer func() { + if clErr := w.Close(); clErr != nil && err == nil { + err = clErr + } + }() + + out = w + } + if r.parallel <= 1 { r.pr.Start(func(t *progress.Task) { t.TotalBytes = func() int64 { @@ -224,9 +250,9 @@ func (r *runner) cat(filename string) (err error) { } if len(r.grep) > 0 { - r.scanFile(rd) + r.scanFile(rd, out) } else { - r.readFile(rd) + r.readFile(rd, out) } cr.Close() @@ -312,10 +338,15 @@ func Main() error { //nolint:funlen,cyclop,gocognit,gocyclo "for example, you can use '-grep bar\\|baz -grep foo' to only keep lines that have (bar OR baz) AND foo") parallel := flag.Int("parallel", 1, "number of parallel readers if multiple files are provided\n"+ + "lines from different files will go to output simultaneously"+ "use 0 for multi-threaded zst decoder (slightly faster at cost of more CPU)") + cpuProfile := flag.String("dbg-cpu-prof", "", "write first 10 seconds of CPU profile to file") memProfile := flag.String("dbg-mem-prof", "", "write heap profile to file after 10 seconds") output := flag.String("output", "", "output to file instead of STDOUT") + outDir := flag.String("out-dir", "", "output to directory instead of STDOUT\n"+ + "files will be written to out dir with original base names\n"+ + "disables output flag") noProgress := flag.Bool("no-progress", false, "disable progress printing") progressJSON := flag.String("progress-json", "", "write current progress to a file") ver := flag.Bool("version", false, "print version and exit") @@ -337,14 +368,15 @@ func Main() error { //nolint:funlen,cyclop,gocognit,gocyclo r := &runner{} r.parallel = *parallel + r.outDir = *outDir - if *output != "" { //nolint:nestif + if *output != "" && *outDir == "" { //nolint:nestif out, err := os.Create(*output) if err != nil { return fmt.Errorf("failed to create output file %s: %w", *output, err) } - w := bufio.NewWriterSize(out, 128*1024) + w := bufio.NewWriterSize(out, 64*1024) r.output = w defer func() { @@ -357,7 +389,7 @@ func Main() error { //nolint:funlen,cyclop,gocognit,gocyclo } }() } else { - w := bufio.NewWriterSize(os.Stdout, 128*1024) + w := bufio.NewWriterSize(os.Stdout, 64*1024) r.output = w defer func() { From 96d3ea337968d8828f4d7a058b8c3d577b5c73bd Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sun, 24 Dec 2023 00:53:59 +0100 Subject: [PATCH 24/36] Disable sync for out-dir --- cmd/catp/catp/app.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index 45a128a..e17af85 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -129,21 +129,21 @@ func (r *runner) scanFile(rd io.Reader, out io.Writer) { atomic.AddInt64(&r.matches, 1) - if r.parallel > 1 { + if r.parallel > 1 && r.outDir == "" { r.mu.Lock() } if _, err := out.Write(append(s.Bytes(), '\n')); err != nil { r.lastErr = err - if r.parallel > 1 { + if r.parallel > 1 && r.outDir == "" { r.mu.Unlock() } return } - if r.parallel > 1 { + if r.parallel > 1 && r.outDir == "" { r.mu.Unlock() } } From 672b13928bbef7e45646f14486d929a5f985d8cf Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sun, 24 Dec 2023 00:58:05 +0100 Subject: [PATCH 25/36] Update PGO --- cmd/catp/default.pgo | Bin 7662 -> 7035 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/cmd/catp/default.pgo b/cmd/catp/default.pgo index f49af97d83621bb1c7e25579a93c740a30fc6c5a..d57301b947e83be3cba41453b57c8e9efda6b5e7 100644 GIT binary patch literal 7035 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 From 1fbf23a48bd4b5ebad16de89e0c358cc65819e93 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sun, 24 Dec 2023 00:59:06 +0100 Subject: [PATCH 26/36] Update PGO --- .github/workflows/release-assets-test.yml | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/workflows/release-assets-test.yml diff --git a/.github/workflows/release-assets-test.yml b/.github/workflows/release-assets-test.yml new file mode 100644 index 0000000..1ba05f4 --- /dev/null +++ b/.github/workflows/release-assets-test.yml @@ -0,0 +1,33 @@ +# This script is provided by github.com/bool64/dev. + +# This script uploads application binaries as GitHub release assets. +name: release-assets-test +on: + pull_request: +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GO_VERSION: 1.22rc1 +jobs: + build: + name: Upload Release Assets + runs-on: ubuntu-latest + steps: + - name: Install Go stable + if: env.GO_VERSION != 'tip' + uses: actions/setup-go@v4 + with: + go-version: ${{ env.GO_VERSION }} + - name: Install Go tip + if: env.GO_VERSION == 'tip' + run: | + curl -sL https://storage.googleapis.com/go-build-snap/go/linux-amd64/$(git ls-remote https://github.com/golang/go.git HEAD | awk '{print $1;}').tar.gz -o gotip.tar.gz + ls -lah gotip.tar.gz + mkdir -p ~/sdk/gotip + tar -C ~/sdk/gotip -xzf gotip.tar.gz + ~/sdk/gotip/bin/go version + echo "PATH=$HOME/go/bin:$HOME/sdk/gotip/bin/:$PATH" >> $GITHUB_ENV + - name: Checkout code + uses: actions/checkout@v3 + - name: Build artifacts + run: | + make release-assets From 634cf6c0010d059dcd9dc851e9d0a633fcdc106a Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sun, 24 Dec 2023 01:00:52 +0100 Subject: [PATCH 27/36] Update CI --- .github/workflows/release-assets-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-assets-test.yml b/.github/workflows/release-assets-test.yml index 1ba05f4..cc44955 100644 --- a/.github/workflows/release-assets-test.yml +++ b/.github/workflows/release-assets-test.yml @@ -6,7 +6,7 @@ on: pull_request: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GO_VERSION: 1.22rc1 + GO_VERSION: '1.22.0-rc.1' jobs: build: name: Upload Release Assets From 8fdf0b08abc9db1694870a0443146f86c53852a2 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sun, 24 Dec 2023 01:09:09 +0100 Subject: [PATCH 28/36] Update CI --- .github/workflows/release-assets-test.yml | 2 ++ .golangci.yml | 4 +++- cmd/catp/catp/app.go | 2 +- go.mod | 2 +- go.sum | 2 ++ 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release-assets-test.yml b/.github/workflows/release-assets-test.yml index cc44955..cc79b13 100644 --- a/.github/workflows/release-assets-test.yml +++ b/.github/workflows/release-assets-test.yml @@ -7,6 +7,8 @@ on: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GO_VERSION: '1.22.0-rc.1' + LINUX_AMD64_BUILD_OPTIONS: '-tags cgo_zstd' + GOAMD64: v3 jobs: build: name: Upload Release Assets diff --git a/.golangci.yml b/.golangci.yml index 6b00dce..c2a2977 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -17,7 +17,9 @@ linters-settings: unparam: check-exported: true funlen: - lines: 70 + lines: 80 + cyclop: + max-complexity: 15 linters: enable-all: true diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index e17af85..0b78cfc 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -182,7 +182,7 @@ func (r *runner) shouldWrite(line []byte) bool { return shouldWrite } -func (r *runner) cat(filename string) (err error) { //nolint:funlen,cyclop +func (r *runner) cat(filename string) (err error) { file, err := os.Open(filename) //nolint:gosec if err != nil { return err diff --git a/go.mod b/go.mod index ac963bc..f409922 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.21 require ( github.com/DataDog/zstd v1.5.5 - github.com/bool64/dev v0.2.32 + github.com/bool64/dev v0.2.33-0.20231224000606-67a281f24e69 github.com/klauspost/compress v1.17.4 github.com/klauspost/pgzip v1.2.6 ) diff --git a/go.sum b/go.sum index 4cdc86c..f4f5255 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/bool64/dev v0.2.32 h1:DRZtloaoH1Igky3zphaUHV9+SLIV2H3lsf78JsJHFg0= github.com/bool64/dev v0.2.32/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= +github.com/bool64/dev v0.2.33-0.20231224000606-67a281f24e69 h1:YoOzmzZv5YEjtoZebxuOhqj+WS/3Q7lg/yKAltiPaTY= +github.com/bool64/dev v0.2.33-0.20231224000606-67a281f24e69/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= From 211637d0400019d8e40e16f5605796f8ae51b43e Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sun, 24 Dec 2023 01:14:17 +0100 Subject: [PATCH 29/36] Update CI --- .github/workflows/release-assets-test.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/release-assets-test.yml b/.github/workflows/release-assets-test.yml index cc79b13..0cb492e 100644 --- a/.github/workflows/release-assets-test.yml +++ b/.github/workflows/release-assets-test.yml @@ -33,3 +33,9 @@ jobs: - name: Build artifacts run: | make release-assets + - name: Builds + uses: actions/upload-artifact@v3 + with: + name: builds + path: | + linux_amd64.tar.gz From 9fdb599fc17d48af5a952c4753b71c261af1a672 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sun, 24 Dec 2023 01:22:17 +0100 Subject: [PATCH 30/36] Update CI --- .github/workflows/release-assets-test.yml | 1 + Makefile | 1 - go.mod | 2 +- go.sum | 6 ++---- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release-assets-test.yml b/.github/workflows/release-assets-test.yml index 0cb492e..6e12a8e 100644 --- a/.github/workflows/release-assets-test.yml +++ b/.github/workflows/release-assets-test.yml @@ -8,6 +8,7 @@ env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GO_VERSION: '1.22.0-rc.1' LINUX_AMD64_BUILD_OPTIONS: '-tags cgo_zstd' + LINUX_AMD64_ENV: "CGO_ENABLED=1" GOAMD64: v3 jobs: build: diff --git a/Makefile b/Makefile index 69cd37b..06f5916 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,6 @@ ifeq ($(DEVGO_PATH),) endif -export GOAMD64 ?= v3 export CGO_ENABLED ?= 0 BUILD_PKG = ./cmd/catp BUILD_LDFLAGS=-s -w diff --git a/go.mod b/go.mod index f409922..fdbc9bc 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.21 require ( github.com/DataDog/zstd v1.5.5 - github.com/bool64/dev v0.2.33-0.20231224000606-67a281f24e69 + github.com/bool64/dev v0.2.33-0.20231224002009-804bdeff9084 github.com/klauspost/compress v1.17.4 github.com/klauspost/pgzip v1.2.6 ) diff --git a/go.sum b/go.sum index f4f5255..2931b40 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,7 @@ github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= -github.com/bool64/dev v0.2.32 h1:DRZtloaoH1Igky3zphaUHV9+SLIV2H3lsf78JsJHFg0= -github.com/bool64/dev v0.2.32/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= -github.com/bool64/dev v0.2.33-0.20231224000606-67a281f24e69 h1:YoOzmzZv5YEjtoZebxuOhqj+WS/3Q7lg/yKAltiPaTY= -github.com/bool64/dev v0.2.33-0.20231224000606-67a281f24e69/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= +github.com/bool64/dev v0.2.33-0.20231224002009-804bdeff9084 h1:fYwP6nQHQxzw+kP+ou1XxkCvTEj40F/aXZzY9Mb7YSk= +github.com/bool64/dev v0.2.33-0.20231224002009-804bdeff9084/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= From 6a83dff4f37c7e1745f26d0be9905ec57889986c Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sun, 24 Dec 2023 01:25:56 +0100 Subject: [PATCH 31/36] Update CI --- .github/workflows/release-assets-test.yml | 1 - Makefile | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/workflows/release-assets-test.yml b/.github/workflows/release-assets-test.yml index 6e12a8e..0cb492e 100644 --- a/.github/workflows/release-assets-test.yml +++ b/.github/workflows/release-assets-test.yml @@ -8,7 +8,6 @@ env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GO_VERSION: '1.22.0-rc.1' LINUX_AMD64_BUILD_OPTIONS: '-tags cgo_zstd' - LINUX_AMD64_ENV: "CGO_ENABLED=1" GOAMD64: v3 jobs: build: diff --git a/Makefile b/Makefile index 06f5916..650b826 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,6 @@ ifeq ($(DEVGO_PATH),) endif -export CGO_ENABLED ?= 0 BUILD_PKG = ./cmd/catp BUILD_LDFLAGS=-s -w From 631bce7f6e8bd803aec51b0b4513937df3984efa Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sun, 24 Dec 2023 01:29:45 +0100 Subject: [PATCH 32/36] Update CI --- .github/workflows/release-assets-test.yml | 1 + go.mod | 2 +- go.sum | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-assets-test.yml b/.github/workflows/release-assets-test.yml index 0cb492e..06e26a8 100644 --- a/.github/workflows/release-assets-test.yml +++ b/.github/workflows/release-assets-test.yml @@ -9,6 +9,7 @@ env: GO_VERSION: '1.22.0-rc.1' LINUX_AMD64_BUILD_OPTIONS: '-tags cgo_zstd' GOAMD64: v3 + CGO_ENABLED: 1 jobs: build: name: Upload Release Assets diff --git a/go.mod b/go.mod index fdbc9bc..d3bd904 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.21 require ( github.com/DataDog/zstd v1.5.5 - github.com/bool64/dev v0.2.33-0.20231224002009-804bdeff9084 + github.com/bool64/dev v0.2.33-0.20231224002521-eccfe6cb66fc github.com/klauspost/compress v1.17.4 github.com/klauspost/pgzip v1.2.6 ) diff --git a/go.sum b/go.sum index 2931b40..691fe01 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/bool64/dev v0.2.33-0.20231224002009-804bdeff9084 h1:fYwP6nQHQxzw+kP+ou1XxkCvTEj40F/aXZzY9Mb7YSk= github.com/bool64/dev v0.2.33-0.20231224002009-804bdeff9084/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= +github.com/bool64/dev v0.2.33-0.20231224002521-eccfe6cb66fc h1:4zTf9ZvStL6mR3AwkNR7IA817Dzn0SB7wmV2luH1sYo= +github.com/bool64/dev v0.2.33-0.20231224002521-eccfe6cb66fc/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= From aca220c2a6756e556eb323c0168cdf2fe9116ea0 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sun, 24 Dec 2023 01:36:58 +0100 Subject: [PATCH 33/36] Update CI --- .github/workflows/release-assets-test.yml | 1 - go.mod | 2 +- go.sum | 6 ++---- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release-assets-test.yml b/.github/workflows/release-assets-test.yml index 06e26a8..0cb492e 100644 --- a/.github/workflows/release-assets-test.yml +++ b/.github/workflows/release-assets-test.yml @@ -9,7 +9,6 @@ env: GO_VERSION: '1.22.0-rc.1' LINUX_AMD64_BUILD_OPTIONS: '-tags cgo_zstd' GOAMD64: v3 - CGO_ENABLED: 1 jobs: build: name: Upload Release Assets diff --git a/go.mod b/go.mod index d3bd904..3191bf2 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.21 require ( github.com/DataDog/zstd v1.5.5 - github.com/bool64/dev v0.2.33-0.20231224002521-eccfe6cb66fc + github.com/bool64/dev v0.2.33-0.20231224003611-6aedc1b597c9 github.com/klauspost/compress v1.17.4 github.com/klauspost/pgzip v1.2.6 ) diff --git a/go.sum b/go.sum index 691fe01..ee421d5 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,7 @@ github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= -github.com/bool64/dev v0.2.33-0.20231224002009-804bdeff9084 h1:fYwP6nQHQxzw+kP+ou1XxkCvTEj40F/aXZzY9Mb7YSk= -github.com/bool64/dev v0.2.33-0.20231224002009-804bdeff9084/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= -github.com/bool64/dev v0.2.33-0.20231224002521-eccfe6cb66fc h1:4zTf9ZvStL6mR3AwkNR7IA817Dzn0SB7wmV2luH1sYo= -github.com/bool64/dev v0.2.33-0.20231224002521-eccfe6cb66fc/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= +github.com/bool64/dev v0.2.33-0.20231224003611-6aedc1b597c9 h1:uKWriuy6kByk+oQpOZauKFwATkrUG1xcS8yWJRei/bc= +github.com/bool64/dev v0.2.33-0.20231224003611-6aedc1b597c9/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= From 36e97b276dd5bbc65c78042bfcd278a5f418760d Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sun, 24 Dec 2023 01:51:25 +0100 Subject: [PATCH 34/36] Update CI --- .github/workflows/release-assets-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-assets-test.yml b/.github/workflows/release-assets-test.yml index 0cb492e..12a5020 100644 --- a/.github/workflows/release-assets-test.yml +++ b/.github/workflows/release-assets-test.yml @@ -12,7 +12,7 @@ env: jobs: build: name: Upload Release Assets - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - name: Install Go stable if: env.GO_VERSION != 'tip' From 674858dd15beb6fe0045c051f71ff600dd477e1c Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sun, 24 Dec 2023 02:00:31 +0100 Subject: [PATCH 35/36] Update CI --- .github/workflows/release-assets-test.yml | 41 ----------------------- .github/workflows/release-assets.yml | 4 ++- go.mod | 2 +- go.sum | 4 +-- 4 files changed, 6 insertions(+), 45 deletions(-) delete mode 100644 .github/workflows/release-assets-test.yml diff --git a/.github/workflows/release-assets-test.yml b/.github/workflows/release-assets-test.yml deleted file mode 100644 index 12a5020..0000000 --- a/.github/workflows/release-assets-test.yml +++ /dev/null @@ -1,41 +0,0 @@ -# This script is provided by github.com/bool64/dev. - -# This script uploads application binaries as GitHub release assets. -name: release-assets-test -on: - pull_request: -env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GO_VERSION: '1.22.0-rc.1' - LINUX_AMD64_BUILD_OPTIONS: '-tags cgo_zstd' - GOAMD64: v3 -jobs: - build: - name: Upload Release Assets - runs-on: ubuntu-20.04 - steps: - - name: Install Go stable - if: env.GO_VERSION != 'tip' - uses: actions/setup-go@v4 - with: - go-version: ${{ env.GO_VERSION }} - - name: Install Go tip - if: env.GO_VERSION == 'tip' - run: | - curl -sL https://storage.googleapis.com/go-build-snap/go/linux-amd64/$(git ls-remote https://github.com/golang/go.git HEAD | awk '{print $1;}').tar.gz -o gotip.tar.gz - ls -lah gotip.tar.gz - mkdir -p ~/sdk/gotip - tar -C ~/sdk/gotip -xzf gotip.tar.gz - ~/sdk/gotip/bin/go version - echo "PATH=$HOME/go/bin:$HOME/sdk/gotip/bin/:$PATH" >> $GITHUB_ENV - - name: Checkout code - uses: actions/checkout@v3 - - name: Build artifacts - run: | - make release-assets - - name: Builds - uses: actions/upload-artifact@v3 - with: - name: builds - path: | - linux_amd64.tar.gz diff --git a/.github/workflows/release-assets.yml b/.github/workflows/release-assets.yml index 5728ae9..06a3906 100644 --- a/.github/workflows/release-assets.yml +++ b/.github/workflows/release-assets.yml @@ -8,7 +8,9 @@ on: - created env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GO_VERSION: 1.22rc1 + GO_VERSION: '1.22.0-rc.1' + LINUX_AMD64_BUILD_OPTIONS: '-tags cgo_zstd' + GOAMD64: v3 jobs: build: name: Upload Release Assets diff --git a/go.mod b/go.mod index 3191bf2..538a66b 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.21 require ( github.com/DataDog/zstd v1.5.5 - github.com/bool64/dev v0.2.33-0.20231224003611-6aedc1b597c9 + github.com/bool64/dev v0.2.33 github.com/klauspost/compress v1.17.4 github.com/klauspost/pgzip v1.2.6 ) diff --git a/go.sum b/go.sum index ee421d5..9c457dc 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= -github.com/bool64/dev v0.2.33-0.20231224003611-6aedc1b597c9 h1:uKWriuy6kByk+oQpOZauKFwATkrUG1xcS8yWJRei/bc= -github.com/bool64/dev v0.2.33-0.20231224003611-6aedc1b597c9/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= +github.com/bool64/dev v0.2.33 h1:ETAcSa8H9w4talcCdSQCCnLX7PMHmuxdLcDl6TpSDj4= +github.com/bool64/dev v0.2.33/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= From 9ccbaa1096f802871cb3b10c73a954faa1399087 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sun, 24 Dec 2023 02:02:20 +0100 Subject: [PATCH 36/36] Update README --- cmd/catp/README.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/cmd/catp/README.md b/cmd/catp/README.md index 0e98765..ab94610 100644 --- a/cmd/catp/README.md +++ b/cmd/catp/README.md @@ -21,10 +21,25 @@ wget https://github.com/bool64/progress/releases/latest/download/linux_amd64.tar Usage of catp: -dbg-cpu-prof string write first 10 seconds of CPU profile to file - -grep string - grep pattern, may contain multiple patterns separated by \| + -dbg-mem-prof string + write heap profile to file after 10 seconds + -grep value + grep pattern, may contain multiple OR patterns separated by \|, + each -grep value is added with AND logic, akin to extra '| grep foo', + for example, you can use '-grep bar\|baz -grep foo' to only keep lines that have (bar OR baz) AND foo + -no-progress + disable progress printing + -out-dir string + output to directory instead of STDOUT + files will be written to out dir with original base names + disables output flag -output string output to file instead of STDOUT + -parallel int + number of parallel readers if multiple files are provided + lines from different files will go to output simultaneouslyuse 0 for multi-threaded zst decoder (slightly faster at cost of more CPU) (default 1) + -progress-json string + write current progress to a file -version print version and exit ```