Re: [racket-users] Racket performance tips

2016-01-18 Thread Gustavo Massaccesi
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
>
> --
> 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 racket-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
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 racket-users+unsubscr...@googlegroups.com.

Re: [racket-users] Racket performance tips

2016-01-18 Thread Brian Adkins
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 

Re: [racket-users] Racket performance tips

2016-01-18 Thread Brian Adkins
On Monday, January 18, 2016 at 11:23:37 AM UTC-5, Brian Adkins wrote:
> [...]
> 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

A couple more notes of interest:

1) I painstakingly created a version that mostly manipulates indexes into byte 
strings so the flow was as follows:
a) a byte string is allocated by "(for ([line-no (in-naturals 1)]"
b) a fixed length byte string is allocated once for an output buffer and reused
c) individual fields were moved from the byte string in (a) directly into the 
buffer in (b) while trimming and deleting embedded backslashes in one operation
d) the buffer was written to the file via write-bytes

All that effort and obfuscation of the code resulted in about 9.5% increase in 
speed. I'm actually glad the speedup wasn't more significant, so I won't be 
tempted to write in that style because it was messy :)

2) Given the heavy use of parse-bytes, I converted the following:

(define (parse-bytes line beg end)
  (bytes-trim (bytes-delete (subbytes line beg end) backslash)))

to this "optimized" hand rolled version that does everything in one pass:

(define (parse-bytes line beg end)
  (define (helper beg end)
(let ([result (make-bytes (- end beg))])
  (let loop ([src beg]
 [dst 0])
(cond [(< src end) (let ([b (bytes-ref line src)])
 (if (= b backslash)
 ;; Skip backslash
 (loop (+ src 1) dst)
 ;; Copy byte to result
 (begin
   (bytes-set! result dst b)
   (loop (+ src 1) (+ dst 1)]
  [else (if (> dst 0)
(subbytes result 0 dst)
#"\\N")]
  (let left ([i beg])
;; Compute i to be the index of the leftmost valid byte
(if (< i end)
(let ([left-byte (bytes-ref line i)])
  (if (or (<= left-byte space)
  (> left-byte max-ascii)
  (= left-byte backslash))
  (left (+ i 1))
  (let right ([j (- end 1)])
;; Compute j to be the index of the rightmost valid byte
(if (>= j i)
(let ([right-byte (bytes-ref line j)])
  (if (or (<= right-byte space)
  (> right-byte max-ascii)
  (= right-byte backslash))
  (right (- j 1))
  (helper i (+ j 1
#"\\N"
#"\\N")))

and the speedup was even less impressive - about 3.5%. I thought that by 
minimizing copying of subbytes multiple times I would gain more, but, again, 
I'm pleased that writing Racket in a more readable/understandable manner 
results in reasonably efficient code.

I'm just about done cleaning up the code, then I'll create a version using 
places and report back with the code and timings and let this thread quiesce :)

-- 
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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Racket performance tips

2016-01-17 Thread Jon Zeppieri
My string-trim uses unsafe ops, but I'm pretty sure it's safe. The (safe) 
string-length at the start ensures we're using a string. The rest are indexing 
and fixnum arithmetic on integers that are guaranteed to be valid indices of 
the string.

Still, if you don't like this, replace the unsafe ops with the corresponding 
safe ones. It will still be much faster than the built-in version.

> On Jan 17, 2016, at 2:54 PM, 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.
> 
> -- 
> 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 racket-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Racket performance tips

2016-01-17 Thread Jon Zeppieri
However, I don't think string representation is the issue, so long as we're
talking about the performance of string-trim.

Racket's string-trim is written for flexibility. It allows you to trim the
left side, the right side, or both sides of the string, and it allows you
to trim characters matching an arbitrary regexp. Ruby's String#strip, on
the other hand, trims whitespace characters from both sides of the string.
If you want to trim only the left side, you use String#lstrip. The right
side? String#rstrip. (And then there are in-place and non-mutating versions
of each.) If you want to trim something other than whitespace you use
something else.

My string-trim is much faster than Racket's built-in one, because it's
completely inflexible, like Ruby's String#strip. Also, because it doesn't
use regexps, it doesn't have another layer of interpretation -- and the
whole thing is visible to the JIT (though I don't know how much difference
that makes in this case).

-Jon




On Sun, Jan 17, 2016 at 3:08 PM, Robby Findler 
wrote:

> Do we know if ruby represents strings the same way Racket does? The
> representation in C clearly admits more efficient implementations of
> relevant operations here, and Ruby's might too.
>
> Robby
>
>
> On Sun, Jan 17, 2016 at 2:00 PM, Jon Zeppieri  wrote:
> > My string-trim uses unsafe ops, but I'm pretty sure it's safe. The
> (safe) string-length at the start ensures we're using a string. The rest
> are indexing and fixnum arithmetic on integers that are guaranteed to be
> valid indices of the string.
> >
> > Still, if you don't like this, replace the unsafe ops with the
> corresponding safe ones. It will still be much faster than the built-in
> version.
> >
> >> On Jan 17, 2016, at 2:54 PM, 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.
> >>
> >> --
> >> 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 racket-users+unsubscr...@googlegroups.com.
> >> For more options, visit https://groups.google.com/d/optout.
> >
> > --
> > 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 racket-users+unsubscr...@googlegroups.com.
> > For more options, visit https://groups.google.com/d/optout.
>

-- 
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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Racket performance tips

2016-01-17 Thread Brian Adkins
On Sunday, January 17, 2016 at 10:09:36 AM UTC-5, Jon Zeppieri wrote:
> Oops: that final else was wrong. If all we encounter in the string is 
> whitespace, the result is the empty string, not the input string, so:
> 
> 
> ;; ===
> 
> (require racket/unsafe/ops)
> 
> 
> (define (string-trim s)
>   (define len (string-length s))
>   
>   (let loop ([i 0])
>     (cond [(unsafe-fx< i len)
>            (cond [(char-whitespace? (unsafe-string-ref s i))
>                   (loop (unsafe-fx+ i 1))]
>                  [else
>                   (let inner ([j (unsafe-fx- len 1)])
>                     (cond [(char-whitespace? (unsafe-string-ref s j))
>                            (inner (unsafe-fx- j 1))]
>                           [else
>                            (substring s i (unsafe-fx+ j 1))]))])]
>             [else
>              ""])))
> ;; ===
> 
> 
> 
> 
> 
> 
> 
> On Sun, Jan 17, 2016 at 1:24 AM, Jon Zeppieri  wrote:
> 
> 
> 
> 
> 
> On Sat, Jan 16, 2016 at 11:29 PM, Brian Adkins  wrote:
> 
> 
> I'm happy to run experiments and report timings though.
> 
> 
> 
> 
> 
> 
> 
> Since the profile suggests that string-trim is the biggest culprit (followed 
> by fprintf), try using this specialized version of string-trim locally:
> 
> 
> ;; ===
> 
> (require racket/unsafe/ops)
> 
> 
> (define (string-trim s)
>   (define len (string-length s))
>   
>   (let loop ([i 0])
>     (cond [(unsafe-fx< i len)
>            (cond [(char-whitespace? (unsafe-string-ref s i))
>                   (loop (unsafe-fx+ i 1))]
>                  [else
>                   (let inner ([j (unsafe-fx- len 1)])
>                     (cond [(char-whitespace? (unsafe-string-ref s j))
>                            (inner (unsafe-fx- j 1))]
>                           [else
>                            (substring s i (unsafe-fx+ j 1))]))])]
>             [else
>              s])))
> ;; ===
> 
> 
> Instead of fprintf-ing the tabbed values, you might try (displayln 
> (string-join fields "\t")). Of course, that requires building a list of 
> strings, which has its own cost.


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%.

-- 
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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Racket performance tips

2016-01-17 Thread Brian Adkins
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.

-- 
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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Racket performance tips

2016-01-17 Thread Alex Knauth

> On Jan 17, 2016, at 2:50 PM, 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%.

Would converting this into a `bytes-trim` function that only works with 
byte-strings help more?


-- 
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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Racket performance tips

2016-01-17 Thread Jon Zeppieri
MRI (the main ruby interpreter) has an odd string representation that's
optimized for shorter strings. There's some info here: [
http://patshaughnessy.net/2012/1/4/never-create-ruby-strings-longer-than-23-characters].
The type is defined here: [
https://github.com/ruby/ruby/blob/af18eafc44bb3bb6aff78f244a67b807500e3e9f/include/ruby/ruby.h#L979
].

-J


On Sun, Jan 17, 2016 at 3:08 PM, Robby Findler 
wrote:

> Do we know if ruby represents strings the same way Racket does? The
> representation in C clearly admits more efficient implementations of
> relevant operations here, and Ruby's might too.
>
> Robby
>
>
> On Sun, Jan 17, 2016 at 2:00 PM, Jon Zeppieri  wrote:
> > My string-trim uses unsafe ops, but I'm pretty sure it's safe. The
> (safe) string-length at the start ensures we're using a string. The rest
> are indexing and fixnum arithmetic on integers that are guaranteed to be
> valid indices of the string.
> >
> > Still, if you don't like this, replace the unsafe ops with the
> corresponding safe ones. It will still be much faster than the built-in
> version.
> >
> >> On Jan 17, 2016, at 2:54 PM, 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.
> >>
> >> --
> >> 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 racket-users+unsubscr...@googlegroups.com.
> >> For more options, visit https://groups.google.com/d/optout.
> >
> > --
> > 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 racket-users+unsubscr...@googlegroups.com.
> > For more options, visit https://groups.google.com/d/optout.
>

-- 
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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Racket performance tips

2016-01-17 Thread Robby Findler
Do we know if ruby represents strings the same way Racket does? The
representation in C clearly admits more efficient implementations of
relevant operations here, and Ruby's might too.

Robby


On Sun, Jan 17, 2016 at 2:00 PM, Jon Zeppieri  wrote:
> My string-trim uses unsafe ops, but I'm pretty sure it's safe. The (safe) 
> string-length at the start ensures we're using a string. The rest are 
> indexing and fixnum arithmetic on integers that are guaranteed to be valid 
> indices of the string.
>
> Still, if you don't like this, replace the unsafe ops with the corresponding 
> safe ones. It will still be much faster than the built-in version.
>
>> On Jan 17, 2016, at 2:54 PM, 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.
>>
>> --
>> 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 racket-users+unsubscr...@googlegroups.com.
>> For more options, visit https://groups.google.com/d/optout.
>
> --
> 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 racket-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Racket performance tips

2016-01-17 Thread Brian Adkins
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

-- 
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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Racket performance tips

2016-01-16 Thread Brian Adkins
On Saturday, January 16, 2016 at 11:22:14 PM UTC-5, Alexis King wrote:
> Those programs appear to depend on input files. Is there any way you could 
> provide those inputs or otherwise make the programs self-contained? I might 
> be interested in taking a look at them, but it’s hard to get a feel for 
> what’s going on without being able to run the programs.
> 
> > On Jan 16, 2016, at 19:32, Brian Adkins wrote:
> > 
> > A while ago, I started a thread about whether Rust or C would be a better 
> > complement to Racket. After much more Rust research/coding, I got very 
> > tired of fighting the compiler, so I decided to blow the dust off my C 
> > skills (I haven't done any serious coding in C since 1996), and code up the 
> > app in C.
> > 
> > In about 2.5 hours, I had coded as much of the app in C as had taken many 
> > more hours in Rust and it was about 2.5x faster and *much* easier to 
> > understand. I knew exactly what I wanted to do for maximum performance, but 
> > I found myself constantly fighting Rust. I've concluded that, for me, C is 
> > a better complement.
> > 
> > Anyway, the purpose for this post is to ask for some assistance in getting 
> > the best performance out of my Racket code. After choosing a different 
> > soundex algorithm, I was a little disappointed in the following runtime 
> > numbers for identical functionality:
> > 
> > Racket = 10.3s
> > Ruby = 7.61s
> > C = 0.472s
> > 
> > Those are numbers for parsing 200K records in a fixed width format to 
> > create a postgres bulk input file. The real data contains 45+M records, so 
> > speed is a consideration (e.g. 1.8 min. for C vs. 38.6 min. for Racket)
> > 
> > It's the fact that Racket is currently slower than Ruby which is bugging 
> > me. Despite my rusty (no pun intended) C skills, I was able to hack a 
> > version that does zero heap allocation and is pretty speedy, so I wouldn't 
> > expect Racket to get close to it. On the other hand, I *would* definitely 
> > hope the Racket version can beat the Ruby version.
> > 
> > Here are the programs:
> > 
> > C: https://gist.github.com/lojic/4369d9d57eb775296c92
> > 
> > Ruby: https://gist.github.com/lojic/2b91fde8e6bbb7bab1cd
> > 
> > Racket: https://gist.github.com/lojic/f306104846d516761952
> > 
> > They have identical output (I measured through the first 4M input records), 
> > and they are very similar (same functions, etc.) in style.
> > 
> > Latest profile output from Racket (using open-output-nowhere as suggested 
> > by Vincent):
> > 
> > https://gist.githubusercontent.com/lojic/db6e02d0d9d88e1d5ced/raw/1002b6e6ee14f2c59b067abe6eac0488a3f2dc7a/profile.txt
> > 
> > Earlier today, I had a hacked up Racket version with manual loops, etc., 
> > but then I thought that I really shouldn't have to resort to that to beat 
> > Ruby, so I returned the Racket code to a form that was most similar to 
> > Ruby. For example:
> > 
> > Ruby:
> > 
> >  def self.parse_string line, beg, len
> >line[beg,len].gsub("\\", '').strip
> >  end
> > 
> > Racket:
> > 
> > (define (parse-string line beg end)
> >  (string-trim (string-replace (substring line beg end) "\\" "")))
> > 
> > But I think the Ruby runtime is a little more optimized currently. In 
> > particular, I suspect string-replace vs. gsub, string-trim vs. strip, etc.
> > 
> > The real fun will come when I use a places version of the Racket code, but 
> > I want to get decent linear speed before parallelizing.
> > 
> > Ruby has no JIT, and both Ruby and Racket of C runtimes, so there doesn't 
> > seem to be any fundamental reason why similar code shouldn't perform better 
> > in Racket.
> > 
> > By the way, I compared Racket 6.2.1 with 6.3 and the latter is 10.4% faster 
> > for this app, so that was encouraging.
> > 
> > Any help is greatly appreciated!
> > 
> > Brian
> > 

Unfortunately, the data is criminal records, so there would be a lot of fields 
to anonymize before I could make it public.

I'm happy to run experiments and report timings though.

-- 
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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Racket performance tips

2016-01-16 Thread Brian Adkins
On Saturday, January 16, 2016 at 11:26:14 PM UTC-5, Neil Van Dyke wrote:
> Your code is very string-ops-heavy, and I would start looking at that.  
> One thing you could do is look for opportunities to construct fewer 
> intermediate strings, including across multiple procedure calls.  You 
> could also look for operations that are expensive, and use 
> less-expensive ones.  If your strings have no multibyte characters, it'd 
> be easier to make it a lot faster with reused bytes I/O buffers and a 
> tons less copying, but you could also try that with multibyte characters 
> (it's harder and slower, though).
> 
> If you get fancy with the optimization, you might end up with a DSL or 
> mini-language for the formats and/or transformation, to simplify the 
> source code while making its behavior more sophisticated.  But maybe you 
> want to focus on a proof-of-concept for the optimizations first, before 
> you go to the work of implementing the DSL.
> 
> BTW, the below comment, from an aborted response to your previous email, 
> doesn't seem to apply to your code, but I'll just note it for the record:
> 
> >
> > Without tracing through the actual code being profiled (not 
> > volunteering!), it's hard to say what the fix is.
> >
> > One little tip, from glancing at "collects/racket/string.rkt"... If 
> > your code happens to be calling `string-trim` with a large number of 
> > different `sep` arguments (different by `eq?`), it looks like it will 
> > be especially slow.  Or if you're calling `string-trim` a huge number 
> > of times with a nonzero number of non-`#f` `sep` arguments, and you're 
> > GCing.  (The implementation assembles regular expressions for non-`#f` 
> > `sep` arguments, and caches them in a weak hash with `eq?` test.)
> 
> BTW, I wouldn't be surprised if `string-trim` could be made faster for 
> the normal case of `sep` being `#f`, though the code doesn't look bad 
> right now.  (The majority of code that people write is not very 
> efficient, and `string-trim` looks better than the norm.) However, it 
> was written in a generalized way, and I don't know if anyone sat down 
> and hand-optimized for the `#f` case specifically. Or, it might have 
> been written a long time ago, and the VM/compiler or strings have 
> changed quite a bit since then, and so the code could benefit from 
> re-hand-optimizing.  (I've done a bunch of that kind of optimizing as a 
> consultant, and it can easily take a few hours for a single procedure, 
> so tends to only happen as-needed.)
> 
> Neil V.

For this app, the data is actually straight ASCII upper case mainframe data :)

Can you elaborate re: "reused bytes I/O buffers "  ?  One of the things I did 
in the C code was to reuse character arrays a lot and never malloc, but I'm 
less familiar with doing similar things in Racket.

I'm not opposed to hand optimizing (the C program was basically one gigantic 
optimization), but to be fair, it seems the same optimizations would need to be 
done to the Ruby code for comparison.

In other words, I have two related, but different goals:

1) I'd like to get to the point of being able to write expressive, "high level" 
code in Racket, in a similar manner as I've been accustomed to with Ruby, but 
with better performance than Ruby. Given Ruby typically trails the pack with 
respect to speed, that doesn't seem unreasonable.

2) I'd also like to get a better idea of practical optimizations that I can use 
with Racket when I need more speed, even if it lessens other aspects of the 
code such as readability, etc. I suppose the string-squeeze function in the 
Racket code is an example of that.

-- 
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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Racket performance tips

2016-01-16 Thread Neil Van Dyke
Your code is very string-ops-heavy, and I would start looking at that.  
One thing you could do is look for opportunities to construct fewer 
intermediate strings, including across multiple procedure calls.  You 
could also look for operations that are expensive, and use 
less-expensive ones.  If your strings have no multibyte characters, it'd 
be easier to make it a lot faster with reused bytes I/O buffers and a 
tons less copying, but you could also try that with multibyte characters 
(it's harder and slower, though).


If you get fancy with the optimization, you might end up with a DSL or 
mini-language for the formats and/or transformation, to simplify the 
source code while making its behavior more sophisticated.  But maybe you 
want to focus on a proof-of-concept for the optimizations first, before 
you go to the work of implementing the DSL.


BTW, the below comment, from an aborted response to your previous email, 
doesn't seem to apply to your code, but I'll just note it for the record:




Without tracing through the actual code being profiled (not 
volunteering!), it's hard to say what the fix is.


One little tip, from glancing at "collects/racket/string.rkt"... If 
your code happens to be calling `string-trim` with a large number of 
different `sep` arguments (different by `eq?`), it looks like it will 
be especially slow.  Or if you're calling `string-trim` a huge number 
of times with a nonzero number of non-`#f` `sep` arguments, and you're 
GCing.  (The implementation assembles regular expressions for non-`#f` 
`sep` arguments, and caches them in a weak hash with `eq?` test.)


BTW, I wouldn't be surprised if `string-trim` could be made faster for 
the normal case of `sep` being `#f`, though the code doesn't look bad 
right now.  (The majority of code that people write is not very 
efficient, and `string-trim` looks better than the norm.) However, it 
was written in a generalized way, and I don't know if anyone sat down 
and hand-optimized for the `#f` case specifically. Or, it might have 
been written a long time ago, and the VM/compiler or strings have 
changed quite a bit since then, and so the code could benefit from 
re-hand-optimizing.  (I've done a bunch of that kind of optimizing as a 
consultant, and it can easily take a few hours for a single procedure, 
so tends to only happen as-needed.)


Neil V.

--
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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Racket performance tips

2016-01-16 Thread WarGrey Gyoudmon Ju
Yes.
What Bytes in Racket is what char * in C.
String treats the chars as a UTF-8 value.

On Sun, Jan 17, 2016 at 12:59 PM, Brian Adkins 
wrote:

> On Saturday, January 16, 2016 at 11:54:05 PM UTC-5, Brian Adkins wrote:
> > On Saturday, January 16, 2016 at 11:26:14 PM UTC-5, Neil Van Dyke wrote:
> > > Your code is very string-ops-heavy, and I would start looking at that.
> > > One thing you could do is look for opportunities to construct fewer
> > > intermediate strings, including across multiple procedure calls.  You
> > > could also look for operations that are expensive, and use
> > > less-expensive ones.  If your strings have no multibyte characters,
> it'd
> > > be easier to make it a lot faster with reused bytes I/O buffers and a
> > > tons less copying, but you could also try that with multibyte
> characters
> > > (it's harder and slower, though).
> > >
> > > If you get fancy with the optimization, you might end up with a DSL or
> > > mini-language for the formats and/or transformation, to simplify the
> > > source code while making its behavior more sophisticated.  But maybe
> you
> > > want to focus on a proof-of-concept for the optimizations first, before
> > > you go to the work of implementing the DSL.
> > >
> > > BTW, the below comment, from an aborted response to your previous
> email,
> > > doesn't seem to apply to your code, but I'll just note it for the
> record:
> > >
> > > >
> > > > Without tracing through the actual code being profiled (not
> > > > volunteering!), it's hard to say what the fix is.
> > > >
> > > > One little tip, from glancing at "collects/racket/string.rkt"... If
> > > > your code happens to be calling `string-trim` with a large number of
> > > > different `sep` arguments (different by `eq?`), it looks like it will
> > > > be especially slow.  Or if you're calling `string-trim` a huge number
> > > > of times with a nonzero number of non-`#f` `sep` arguments, and
> you're
> > > > GCing.  (The implementation assembles regular expressions for
> non-`#f`
> > > > `sep` arguments, and caches them in a weak hash with `eq?` test.)
> > >
> > > BTW, I wouldn't be surprised if `string-trim` could be made faster for
> > > the normal case of `sep` being `#f`, though the code doesn't look bad
> > > right now.  (The majority of code that people write is not very
> > > efficient, and `string-trim` looks better than the norm.) However, it
> > > was written in a generalized way, and I don't know if anyone sat down
> > > and hand-optimized for the `#f` case specifically. Or, it might have
> > > been written a long time ago, and the VM/compiler or strings have
> > > changed quite a bit since then, and so the code could benefit from
> > > re-hand-optimizing.  (I've done a bunch of that kind of optimizing as a
> > > consultant, and it can easily take a few hours for a single procedure,
> > > so tends to only happen as-needed.)
> > >
> > > Neil V.
> >
> > For this app, the data is actually straight ASCII upper case mainframe
> data :)
> >
> > Can you elaborate re: "reused bytes I/O buffers "  ?  One of the things
> I did in the C code was to reuse character arrays a lot and never malloc,
> but I'm less familiar with doing similar things in Racket.
> >
> > I'm not opposed to hand optimizing (the C program was basically one
> gigantic optimization), but to be fair, it seems the same optimizations
> would need to be done to the Ruby code for comparison.
> >
> > In other words, I have two related, but different goals:
> >
> > 1) I'd like to get to the point of being able to write expressive, "high
> level" code in Racket, in a similar manner as I've been accustomed to with
> Ruby, but with better performance than Ruby. Given Ruby typically trails
> the pack with respect to speed, that doesn't seem unreasonable.
> >
> > 2) I'd also like to get a better idea of practical optimizations that I
> can use with Racket when I need more speed, even if it lessens other
> aspects of the code such as readability, etc. I suppose the string-squeeze
> function in the Racket code is an example of that.
>
> So, maybe replace in-lines with in-bytes-lines on line 31 of
> https://gist.github.com/lojic/f306104846d516761952 and flow Byte Strings
> through the app instead of Strings given the source being ASCII chars ?
>
> --
> 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 racket-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Racket performance tips

2016-01-16 Thread Brian Adkins
On Saturday, January 16, 2016 at 11:54:05 PM UTC-5, Brian Adkins wrote:
> On Saturday, January 16, 2016 at 11:26:14 PM UTC-5, Neil Van Dyke wrote:
> > Your code is very string-ops-heavy, and I would start looking at that.  
> > One thing you could do is look for opportunities to construct fewer 
> > intermediate strings, including across multiple procedure calls.  You 
> > could also look for operations that are expensive, and use 
> > less-expensive ones.  If your strings have no multibyte characters, it'd 
> > be easier to make it a lot faster with reused bytes I/O buffers and a 
> > tons less copying, but you could also try that with multibyte characters 
> > (it's harder and slower, though).
> > 
> > If you get fancy with the optimization, you might end up with a DSL or 
> > mini-language for the formats and/or transformation, to simplify the 
> > source code while making its behavior more sophisticated.  But maybe you 
> > want to focus on a proof-of-concept for the optimizations first, before 
> > you go to the work of implementing the DSL.
> > 
> > BTW, the below comment, from an aborted response to your previous email, 
> > doesn't seem to apply to your code, but I'll just note it for the record:
> > 
> > >
> > > Without tracing through the actual code being profiled (not 
> > > volunteering!), it's hard to say what the fix is.
> > >
> > > One little tip, from glancing at "collects/racket/string.rkt"... If 
> > > your code happens to be calling `string-trim` with a large number of 
> > > different `sep` arguments (different by `eq?`), it looks like it will 
> > > be especially slow.  Or if you're calling `string-trim` a huge number 
> > > of times with a nonzero number of non-`#f` `sep` arguments, and you're 
> > > GCing.  (The implementation assembles regular expressions for non-`#f` 
> > > `sep` arguments, and caches them in a weak hash with `eq?` test.)
> > 
> > BTW, I wouldn't be surprised if `string-trim` could be made faster for 
> > the normal case of `sep` being `#f`, though the code doesn't look bad 
> > right now.  (The majority of code that people write is not very 
> > efficient, and `string-trim` looks better than the norm.) However, it 
> > was written in a generalized way, and I don't know if anyone sat down 
> > and hand-optimized for the `#f` case specifically. Or, it might have 
> > been written a long time ago, and the VM/compiler or strings have 
> > changed quite a bit since then, and so the code could benefit from 
> > re-hand-optimizing.  (I've done a bunch of that kind of optimizing as a 
> > consultant, and it can easily take a few hours for a single procedure, 
> > so tends to only happen as-needed.)
> > 
> > Neil V.
> 
> For this app, the data is actually straight ASCII upper case mainframe data :)
> 
> Can you elaborate re: "reused bytes I/O buffers "  ?  One of the things I did 
> in the C code was to reuse character arrays a lot and never malloc, but I'm 
> less familiar with doing similar things in Racket.
> 
> I'm not opposed to hand optimizing (the C program was basically one gigantic 
> optimization), but to be fair, it seems the same optimizations would need to 
> be done to the Ruby code for comparison.
> 
> In other words, I have two related, but different goals:
> 
> 1) I'd like to get to the point of being able to write expressive, "high 
> level" code in Racket, in a similar manner as I've been accustomed to with 
> Ruby, but with better performance than Ruby. Given Ruby typically trails the 
> pack with respect to speed, that doesn't seem unreasonable.
> 
> 2) I'd also like to get a better idea of practical optimizations that I can 
> use with Racket when I need more speed, even if it lessens other aspects of 
> the code such as readability, etc. I suppose the string-squeeze function in 
> the Racket code is an example of that.

So, maybe replace in-lines with in-bytes-lines on line 31 of 
https://gist.github.com/lojic/f306104846d516761952 and flow Byte Strings 
through the app instead of Strings given the source being ASCII chars ?

-- 
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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Racket performance tips

2016-01-16 Thread Neil Van Dyke

Brian Adkins wrote on 01/16/2016 11:54 PM:

Can you elaborate re: "reused bytes I/O buffers "  ?  One of the things I did 
in the C code was to reuse character arrays a lot and never malloc, but I'm less familiar 
with doing similar things in Racket.


Look at `read-bytes!`, `read-bytes-avail!`, and related procedures. 
Preferably on a buffer you reuse for each record.  And remember that you 
don't always need to copy -- you can pass around byte range indexes, and 
you can even mutate the buffer.  Then do something like you would in C 
(just with no pointer arithmetic, but at least you get safety and access 
to the higher-level language when you want).



1) I'd like to get to the point of being able to write expressive, "high level" 
code in Racket, in a similar manner as I've been accustomed to with Ruby, but with better 
performance than Ruby. Given Ruby typically trails the pack with respect to speed, that 
doesn't seem unreasonable.


I've found Racket performance acceptable for most purposes, including 
the general kind of records processing you're doing.  I suspect the 
difference you're seeing in this case is due to something like some of 
Ruby's string ops being faster than Racket's (if that's true).


Neil V.

--
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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Racket performance tips

2016-01-16 Thread Jon Zeppieri
On Sat, Jan 16, 2016 at 11:29 PM, Brian Adkins 
wrote:

>
> I'm happy to run experiments and report timings though.
>
>
Since the profile suggests that string-trim is the biggest culprit
(followed by fprintf), try using this specialized version of string-trim
locally:

;; ===
(require racket/unsafe/ops)

(define (string-trim s)
  (define len (string-length s))

  (let loop ([i 0])
(cond [(unsafe-fx< i len)
   (cond [(char-whitespace? (unsafe-string-ref s i))
  (loop (unsafe-fx+ i 1))]
 [else
  (let inner ([j (unsafe-fx- len 1)])
(cond [(char-whitespace? (unsafe-string-ref s j))
   (inner (unsafe-fx- j 1))]
  [else
   (substring s i (unsafe-fx+ j 1))]))])]
[else
 s])))
;; ===

Instead of fprintf-ing the tabbed values, you might try (displayln
(string-join fields "\t")). Of course, that requires building a list of
strings, which has its own cost.

-- 
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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.