On Monday, January 18, 2016 at 10:23:56 AM UTC-5, gustavo wrote: > I have a few minor stile comments: > > *** I'd replace > (define backslash 92) > with > (define backslash (char->integer #\\)) > to improve legibility. > And do the same replacement for other magic numbers. After > optimization, both versions are identical. > > [The only site where this would cause a difference is in code like > (for ([i (in-range 92)]) ...) > but you are not using something like this.] > > > *** In few spots, you use `null` as "do nothing in this case", for > example in line 38. I think it's more idiomatic to use `(void)`. > > *** In line 328, I it possible to do this? Replace > > ;;[[[ > ;; 5. Remove all occurrences of AEIOU, except first letter > (define len2 (bytes-length str4)) > (define str5(bytes-append > (subbytes str4 0 1) > (bytes-delete-pred > (if (> len2 1) (subbytes str4 1 len2) #"") > (λ (b) ...)))) > ;; 6. If first symbol is a digit replace it with letter saved on step 1. > (when (byte-numeric? (bytes-ref str5 0)) > (bytes-set! str5 0 first_letter)) > ;;;]]] > > with this > > ;;[[[ > ;; 5. Remove all occurrences of AEIOU, except first letter > (define len2 (bytes-length str4)) > (define str5(bytes-append > #"?" > (bytes-delete-pred > (if (> len2 1) (subbytes str4 1 len2) #"") > (λ (b) ...)))) > ;; 6. Replace firt symbol with letter saved on step 1. > (bytes-set! str5 0 first_letter) > ;;;]]] > > or this: > > ;;[[[ > ;; 5. Remove all occurrences > (define len2 (bytes-length str4)) > (when (>= len2 1) > (bytes-set! str4 0 (char->integer #\?)) > (define str5 > (bytes-delete-pred > str4 > (λ (b) ...)))) > ;; 6. Replace firt symbol with letter saved on step 1. > (when (>= len2 1) > (bytes-set! str5 0 first_letter)) > ;;;]]] > > I hope I'm not missing a corner case. I estimate that with the 200K > fields this will reduce the time from 2.5s to 2.4s. > > > *** I tried a few more changes that avoid allocating intermediate > bytes, but they are more complex and with 200K rows I estimate that > the difference in run time would be only 0.02s. If I find something > bigger, I'll write again. > > Gustavo > > PS: How many "JOHN"s do you have? Have you considered caching the > soundex of the names. But I'm not sure if this would be faster. > > On Sun, Jan 17, 2016 at 10:13 PM, Brian Adkins wrote: > > On Sunday, January 17, 2016 at 2:54:39 PM UTC-5, Brian Adkins wrote: > >> On Sunday, January 17, 2016 at 2:50:19 PM UTC-5, Brian Adkins wrote: > >> > > >> > With built-in string-trim, the lowest of three runs was 10293. Using > >> > your string-trim the lowest of three runs was 7618, so it reduced the > >> > runtime by 26%. > >> > >> Although, I probably should've mentioned that I'm not particularly > >> interested in unsafe optimizations. I already have a very fast C program > >> if I'm willing to risk unsafe behavior, so for Racket, I'd like to retain > >> safety. > >> > >> Having said that, I'm pretty sure a combination of using Byte Strings and > >> manually optimizing string-trim & string-replace (or skipping them in some > >> cases) will get under the Ruby time. > > > > Yay - success! :) > > > > I changed all strings to byte strings while leaving the style of the code > > very similar. It made a significant difference. Of course, I also gained > > the benefit if handwritten bytes-split, bytes-replace, bytes-delete, > > bytes-trim, etc. which were narrowly defined just for this app. > > > > Timings on a 200K line file are now: > > > > Ruby = 7.53s > > Racket = 2.52s (was 10.3s) > > > > The string version of the Racket program was over 4x slower. I'm quite > > satisfied with being 3x faster than Ruby with a similar coding style given > > this is really in Ruby's sweet spot i.e. text munging. > > > > New code is here: > > > > https://gist.github.com/lojic/892049e617637903f982 > > > > I think my next step will be to create a version that uses places. > > make-shared-bytes may be useful for that. I'll report back with timings. I > > have a 4 core macbook pro w/ 8 hyperthreads - no idea whether the > > hyperthreads are actually useful, but if I can get a 3x speedup with 4 > > cores, I'd be pretty pleased. > > > > I suppose the following is a reasonable architecture: > > > > 1 place for reading the input file and placing a record in a input queue > > N places (one per core) to read from the input queue, process and place in > > an output queue > > 1 place for reading the output queue and writing to either of two output > > files
Thanks. Yes, I have a lot of cleanup to do - I basically hacked this together as fast as I could to experiment. I had wondered about caching the soundex values in the past, so I just coded up a version and concluded it's not helpful, but I think part of that is Racket has some efficiency issues with growing hashes. For the smaller, 200K line, file, there was some improvement, but as I increased the percentage improvement dropped significantly and approached zero. I think the remaining "low hanging fruit" is: 1) Reuse byte string buffers and basically manipulate indexes 2) Parallelize with places -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.

