Re: possibly a Clojure question or possibly an AWS question: slow writes to durable-queue

2017-10-13 Thread Ravindra Jaju
I've faced this issue before, and I'd hazard a guess that like me, it could
be related to the IOPS settings.

AWS' IO performance is highly variable, and you get good performance in
bursts, in very low volumes, and generally only initially for long runs.
Which kind of makes sense, unless you reserve.

durable-queue has a good amount of round-tripping for each 'task'
(depending on how often it syncs too). Combine that with your general
applications logging (debug mode? info mode?) and it simply adds up
overwhelming the entire IO system.

Our volumes were large (both data-, and number of instances-wise). My
workaround was to create a RAM-based filesystem and hold the durable-queue
on it. Which is okay for our use-case because if the machine were to be
killed, we didn't care about the "durability" across instance reboots as
such. Our perf issues as far as durable-queues go vanished! As an aside,
reducing the log-levels too affected app performance on AWS, for the
default config instances.

Memory consumption, though an indicator of problems, isn't necessarily a
direct indicator of things. The IO-backlog's backpressure on the entire JVM
runtime is also a possible reason. At least in my case, it went away once
the durable-queue was moved to the RAM-FS.

Good luck!

-- 
jaju

On Fri, Oct 13, 2017 at 10:05 AM, <lawrence.krub...@gmail.com> wrote:

> Following Daniel Compton's suggestion, I turned on logging for GC. I don't
> see it happening more often, but the slow down does seem related to the
> moment when the app hits the maximum memory allowed. It had been running
> with 4G, so I increased that to 7G, so it goes longer now before it hits
> 98% memory usage, but it does hit it eventually and then everything crawls
> to a very slow speed. Not sure how much memory I would have to use to avoid
> using up almost all of the memory. I suppose I'll figure that out via trial
> and error. Until I can figure that out, nearly all other performance tricks
> seems a bit besides the point.
>
>
>
> On Thursday, October 12, 2017 at 9:01:23 PM UTC-4, Nathan Fisher wrote:
>>
>> Hi!
>>
>> Can you change one of the variables? Specifically can you replicate this
>> on your local machine? If it happens locally then I would focus on
>> something in the JVM eco-system.
>>
>> If you can't replicate it locally then it's possibly AWS specific. It
>> sounds like you're using a t2.large or m4.xlarge. If it's the prior you may
>> very well be contending between with your network bandwidth. EC2's host
>> drive (EBS) is a networked drive which is split between your standard
>> network traffic and the drive volume. If that's the issue then you might
>> need to look at provisioned IOPs. A quick(ish) way to test that hypothesis
>> is to provision a host with high networking performance and provisioned
>> IOPs.
>>
>> Cheers,
>> Nathan
>>
>> On Fri, 13 Oct 2017 at 00:05 <lawrence...@gmail.com> wrote:
>>
>>> Daniel Compton, good suggestion. I've increased the memory to see if I
>>> can postpone the GCs, and I'll log that more carefully.
>>>
>>>
>>> On Wednesday, October 11, 2017 at 8:35:44 PM UTC-4, Daniel Compton wrote:
>>>
>>>> Without more information it's hard to tell, but this looks a like it
>>>> could be a garbage collection issue. Can you run your test again and add
>>>> some logging/monitoring to show each garbage collection? If my hunch is
>>>> right, you'll see garbage collections getting more and more frequent until
>>>> they take up nearly all the CPU time, preventing much forward progress
>>>> writing to the queue.
>>>>
>>>> If it's AWS based throttling, then CloudWatch monitoring
>>>> http://docs.aws.amazon.com/AWSEC2/latest/UserGuid
>>>> e/monitoring-volume-status.html#using_cloudwatch_ebs might show you
>>>> some hints. You could also test with an NVMe drive attached, just to see if
>>>> disk bandwidth is the issue.
>>>>
>>>> On Thu, Oct 12, 2017 at 11:58 AM Justin Smith <noise...@gmail.com>
>>>> wrote:
>>>>
>>> a small thing here, if memory usage is important you should be building
>>>>> and running an uberjar instead of using lein on the server (this also has
>>>>> other benefits), and if you are doing that your project.clj jvm-opts are
>>>>> not used, you have to configure your java command line in aws instead
>>>>>
>>>>> On Wed, Oct 11, 2017 at 3:52 PM <lawrence...@gmail.com> wrote:
>>>>>
>>>> I can't figure out if this is a Clojure question or an AWS question.
>>>&g

Re: possibly a Clojure question or possibly an AWS question: slow writes to durable-queue

2017-10-13 Thread Nathan Fisher
It sounds like you have a memory leak. I would look at addressing that
before any performance tricks.
On Fri, 13 Oct 2017 at 05:35, <lawrence.krub...@gmail.com> wrote:

> Following Daniel Compton's suggestion, I turned on logging for GC. I don't
> see it happening more often, but the slow down does seem related to the
> moment when the app hits the maximum memory allowed. It had been running
> with 4G, so I increased that to 7G, so it goes longer now before it hits
> 98% memory usage, but it does hit it eventually and then everything crawls
> to a very slow speed. Not sure how much memory I would have to use to avoid
> using up almost all of the memory. I suppose I'll figure that out via trial
> and error. Until I can figure that out, nearly all other performance tricks
> seems a bit besides the point.
>
>
>
> On Thursday, October 12, 2017 at 9:01:23 PM UTC-4, Nathan Fisher wrote:
>
>> Hi!
>>
>> Can you change one of the variables? Specifically can you replicate this
>> on your local machine? If it happens locally then I would focus on
>> something in the JVM eco-system.
>>
>> If you can't replicate it locally then it's possibly AWS specific. It
>> sounds like you're using a t2.large or m4.xlarge. If it's the prior you may
>> very well be contending between with your network bandwidth. EC2's host
>> drive (EBS) is a networked drive which is split between your standard
>> network traffic and the drive volume. If that's the issue then you might
>> need to look at provisioned IOPs. A quick(ish) way to test that hypothesis
>> is to provision a host with high networking performance and provisioned
>> IOPs.
>>
>> Cheers,
>> Nathan
>>
>> On Fri, 13 Oct 2017 at 00:05 <lawrence...@gmail.com> wrote:
>>
>>> Daniel Compton, good suggestion. I've increased the memory to see if I
>>> can postpone the GCs, and I'll log that more carefully.
>>>
>>>
>>> On Wednesday, October 11, 2017 at 8:35:44 PM UTC-4, Daniel Compton wrote:
>>>
>>>> Without more information it's hard to tell, but this looks a like it
>>>> could be a garbage collection issue. Can you run your test again and add
>>>> some logging/monitoring to show each garbage collection? If my hunch is
>>>> right, you'll see garbage collections getting more and more frequent until
>>>> they take up nearly all the CPU time, preventing much forward progress
>>>> writing to the queue.
>>>>
>>>> If it's AWS based throttling, then CloudWatch monitoring
>>>> http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/monitoring-volume-status.html#using_cloudwatch_ebs
>>>>  might
>>>> show you some hints. You could also test with an NVMe drive attached, just
>>>> to see if disk bandwidth is the issue.
>>>>
>>>> On Thu, Oct 12, 2017 at 11:58 AM Justin Smith <noise...@gmail.com>
>>>> wrote:
>>>>
>>> a small thing here, if memory usage is important you should be building
>>>>> and running an uberjar instead of using lein on the server (this also has
>>>>> other benefits), and if you are doing that your project.clj jvm-opts are
>>>>> not used, you have to configure your java command line in aws instead
>>>>>
>>>>> On Wed, Oct 11, 2017 at 3:52 PM <lawrence...@gmail.com> wrote:
>>>>>
>>>> I can't figure out if this is a Clojure question or an AWS question.
>>>>>> And if it is a Clojure question, I can't figure out if it is more of a
>>>>>> general JVM question, or if it is specific to some library such as
>>>>>> durable-queue. I can redirect my question elsewhere, if people think this
>>>>>> is an AWS question.
>>>>>>
>>>>>> In my project.clj, I try to give my app a lot of memory:
>>>>>>
>>>>>>   :jvm-opts ["-Xms7g" "-Xmx7g" "-XX:-UseCompressedOops"])
>>>>>>
>>>>>> And the app starts off pulling data from MySQL and writing it to
>>>>>> Durable-Queue at a rapid rate. (
>>>>>> https://github.com/Factual/durable-queue )
>>>>>>
>>>>>> I have some logging set up to report every 30 seconds.
>>>>>>
>>>>>> :enqueued 370137,
>>>>>>
>>>>>> 30 seconds later:
>>>>>>
>>>>>> :enqueued 608967,
>>>>>>
>>>>>> 30 seconds later:
>>>>>>

Re: possibly a Clojure question or possibly an AWS question: slow writes to durable-queue

2017-10-12 Thread lawrence . krubner
Following Daniel Compton's suggestion, I turned on logging for GC. I don't 
see it happening more often, but the slow down does seem related to the 
moment when the app hits the maximum memory allowed. It had been running 
with 4G, so I increased that to 7G, so it goes longer now before it hits 
98% memory usage, but it does hit it eventually and then everything crawls 
to a very slow speed. Not sure how much memory I would have to use to avoid 
using up almost all of the memory. I suppose I'll figure that out via trial 
and error. Until I can figure that out, nearly all other performance tricks 
seems a bit besides the point. 



On Thursday, October 12, 2017 at 9:01:23 PM UTC-4, Nathan Fisher wrote:
>
> Hi!
>
> Can you change one of the variables? Specifically can you replicate this 
> on your local machine? If it happens locally then I would focus on 
> something in the JVM eco-system.
>
> If you can't replicate it locally then it's possibly AWS specific. It 
> sounds like you're using a t2.large or m4.xlarge. If it's the prior you may 
> very well be contending between with your network bandwidth. EC2's host 
> drive (EBS) is a networked drive which is split between your standard 
> network traffic and the drive volume. If that's the issue then you might 
> need to look at provisioned IOPs. A quick(ish) way to test that hypothesis 
> is to provision a host with high networking performance and provisioned 
> IOPs.
>
> Cheers,
> Nathan
>
> On Fri, 13 Oct 2017 at 00:05 <lawrence...@gmail.com > wrote:
>
>> Daniel Compton, good suggestion. I've increased the memory to see if I 
>> can postpone the GCs, and I'll log that more carefully. 
>>
>>
>> On Wednesday, October 11, 2017 at 8:35:44 PM UTC-4, Daniel Compton wrote:
>>
>>> Without more information it's hard to tell, but this looks a like it 
>>> could be a garbage collection issue. Can you run your test again and add 
>>> some logging/monitoring to show each garbage collection? If my hunch is 
>>> right, you'll see garbage collections getting more and more frequent until 
>>> they take up nearly all the CPU time, preventing much forward progress 
>>> writing to the queue.
>>>
>>> If it's AWS based throttling, then CloudWatch monitoring 
>>> http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/monitoring-volume-status.html#using_cloudwatch_ebs
>>>  might 
>>> show you some hints. You could also test with an NVMe drive attached, just 
>>> to see if disk bandwidth is the issue.
>>>
>>> On Thu, Oct 12, 2017 at 11:58 AM Justin Smith <noise...@gmail.com> 
>>> wrote:
>>>
>> a small thing here, if memory usage is important you should be building 
>>>> and running an uberjar instead of using lein on the server (this also has 
>>>> other benefits), and if you are doing that your project.clj jvm-opts are 
>>>> not used, you have to configure your java command line in aws instead
>>>>
>>>> On Wed, Oct 11, 2017 at 3:52 PM <lawrence...@gmail.com> wrote:
>>>>
>>> I can't figure out if this is a Clojure question or an AWS question. And 
>>>>> if it is a Clojure question, I can't figure out if it is more of a 
>>>>> general 
>>>>> JVM question, or if it is specific to some library such as durable-queue. 
>>>>> I 
>>>>> can redirect my question elsewhere, if people think this is an AWS 
>>>>> question. 
>>>>>
>>>>> In my project.clj, I try to give my app a lot of memory:
>>>>>
>>>>>   :jvm-opts ["-Xms7g" "-Xmx7g" "-XX:-UseCompressedOops"])
>>>>>
>>>>> And the app starts off pulling data from MySQL and writing it to 
>>>>> Durable-Queue at a rapid rate. ( 
>>>>> https://github.com/Factual/durable-queue )
>>>>>
>>>>> I have some logging set up to report every 30 seconds.
>>>>>
>>>>> :enqueued 370137,
>>>>>
>>>>> 30 seconds later:
>>>>>
>>>>> :enqueued 608967,
>>>>>
>>>>> 30 seconds later: 
>>>>>
>>>>> :enqueued 828950,
>>>>>
>>>>> It's a dramatic slowdown. The app is initially writing to the queue at 
>>>>> faster than 10,000 documents a second, but it slows steadily, and after 
>>>>> 10 
>>>>> minutes it writes less than 1,000 documents per second. Since I have to 
>>>>> write a few million documents, 10,000 a second is the slo

Re: possibly a Clojure question or possibly an AWS question: slow writes to durable-queue

2017-10-12 Thread Nathan Fisher
Hi!

Can you change one of the variables? Specifically can you replicate this on
your local machine? If it happens locally then I would focus on something
in the JVM eco-system.

If you can't replicate it locally then it's possibly AWS specific. It
sounds like you're using a t2.large or m4.xlarge. If it's the prior you may
very well be contending between with your network bandwidth. EC2's host
drive (EBS) is a networked drive which is split between your standard
network traffic and the drive volume. If that's the issue then you might
need to look at provisioned IOPs. A quick(ish) way to test that hypothesis
is to provision a host with high networking performance and provisioned
IOPs.

Cheers,
Nathan

On Fri, 13 Oct 2017 at 00:05 <lawrence.krub...@gmail.com> wrote:

> Daniel Compton, good suggestion. I've increased the memory to see if I can
> postpone the GCs, and I'll log that more carefully.
>
>
> On Wednesday, October 11, 2017 at 8:35:44 PM UTC-4, Daniel Compton wrote:
>
>> Without more information it's hard to tell, but this looks a like it
>> could be a garbage collection issue. Can you run your test again and add
>> some logging/monitoring to show each garbage collection? If my hunch is
>> right, you'll see garbage collections getting more and more frequent until
>> they take up nearly all the CPU time, preventing much forward progress
>> writing to the queue.
>>
>> If it's AWS based throttling, then CloudWatch monitoring
>> http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/monitoring-volume-status.html#using_cloudwatch_ebs
>>  might
>> show you some hints. You could also test with an NVMe drive attached, just
>> to see if disk bandwidth is the issue.
>>
>> On Thu, Oct 12, 2017 at 11:58 AM Justin Smith <noise...@gmail.com> wrote:
>>
> a small thing here, if memory usage is important you should be building
>>> and running an uberjar instead of using lein on the server (this also has
>>> other benefits), and if you are doing that your project.clj jvm-opts are
>>> not used, you have to configure your java command line in aws instead
>>>
>>> On Wed, Oct 11, 2017 at 3:52 PM <lawrence...@gmail.com> wrote:
>>>
>> I can't figure out if this is a Clojure question or an AWS question. And
>>>> if it is a Clojure question, I can't figure out if it is more of a general
>>>> JVM question, or if it is specific to some library such as durable-queue. I
>>>> can redirect my question elsewhere, if people think this is an AWS
>>>> question.
>>>>
>>>> In my project.clj, I try to give my app a lot of memory:
>>>>
>>>>   :jvm-opts ["-Xms7g" "-Xmx7g" "-XX:-UseCompressedOops"])
>>>>
>>>> And the app starts off pulling data from MySQL and writing it to
>>>> Durable-Queue at a rapid rate. (
>>>> https://github.com/Factual/durable-queue )
>>>>
>>>> I have some logging set up to report every 30 seconds.
>>>>
>>>> :enqueued 370137,
>>>>
>>>> 30 seconds later:
>>>>
>>>> :enqueued 608967,
>>>>
>>>> 30 seconds later:
>>>>
>>>> :enqueued 828950,
>>>>
>>>> It's a dramatic slowdown. The app is initially writing to the queue at
>>>> faster than 10,000 documents a second, but it slows steadily, and after 10
>>>> minutes it writes less than 1,000 documents per second. Since I have to
>>>> write a few million documents, 10,000 a second is the slowest speed I can
>>>> live with.
>>>>
>>>> The queues are in the /tmp folder of an AWS instance that has plenty of
>>>> disk space, 4 CPUs, and 16 gigs of RAM.
>>>>
>>>> Why does the app slow down so much? I had 4 thoughts:
>>>>
>>>> 1.) the app struggles as it hits a memory limit
>>>>
>>>> 2.) memory bandwidth is the problem
>>>>
>>>> 3.) AWS is enforcing some weird IOPS limit
>>>>
>>>> 4.) durable-queue is misbehaving
>>>>
>>>> As to possibility #1, I notice the app starts like this:
>>>>
>>>> Memory in use (percentage/used/max-heap): (\"66%\" \"2373M\" \"3568M\")
>>>>
>>>> but 60 seconds later I see:
>>>>
>>>> Memory in use (percentage/used/max-heap): (\"94%\" \"3613M\" \"3819M\")
>>>>
>>>> So I've run out of allowed memory. But why is that? I thought I gave
>>>> this app 7 gigs:
>

Re: possibly a Clojure question or possibly an AWS question: slow writes to durable-queue

2017-10-12 Thread lawrence . krubner
Daniel Compton, good suggestion. I've increased the memory to see if I can 
postpone the GCs, and I'll log that more carefully. 


On Wednesday, October 11, 2017 at 8:35:44 PM UTC-4, Daniel Compton wrote:
>
> Without more information it's hard to tell, but this looks a like it could 
> be a garbage collection issue. Can you run your test again and add some 
> logging/monitoring to show each garbage collection? If my hunch is right, 
> you'll see garbage collections getting more and more frequent until they 
> take up nearly all the CPU time, preventing much forward progress writing 
> to the queue.
>
> If it's AWS based throttling, then CloudWatch monitoring 
> http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/monitoring-volume-status.html#using_cloudwatch_ebs
>  might 
> show you some hints. You could also test with an NVMe drive attached, just 
> to see if disk bandwidth is the issue.
>
> On Thu, Oct 12, 2017 at 11:58 AM Justin Smith <noise...@gmail.com 
> > wrote:
>
>> a small thing here, if memory usage is important you should be building 
>> and running an uberjar instead of using lein on the server (this also has 
>> other benefits), and if you are doing that your project.clj jvm-opts are 
>> not used, you have to configure your java command line in aws instead
>>
>> On Wed, Oct 11, 2017 at 3:52 PM <lawrence...@gmail.com > 
>> wrote:
>>
>>> I can't figure out if this is a Clojure question or an AWS question. And 
>>> if it is a Clojure question, I can't figure out if it is more of a general 
>>> JVM question, or if it is specific to some library such as durable-queue. I 
>>> can redirect my question elsewhere, if people think this is an AWS 
>>> question. 
>>>
>>> In my project.clj, I try to give my app a lot of memory:
>>>
>>>   :jvm-opts ["-Xms7g" "-Xmx7g" "-XX:-UseCompressedOops"])
>>>
>>> And the app starts off pulling data from MySQL and writing it to 
>>> Durable-Queue at a rapid rate. ( 
>>> https://github.com/Factual/durable-queue )
>>>
>>> I have some logging set up to report every 30 seconds.
>>>
>>> :enqueued 370137,
>>>
>>> 30 seconds later:
>>>
>>> :enqueued 608967,
>>>
>>> 30 seconds later: 
>>>
>>> :enqueued 828950,
>>>
>>> It's a dramatic slowdown. The app is initially writing to the queue at 
>>> faster than 10,000 documents a second, but it slows steadily, and after 10 
>>> minutes it writes less than 1,000 documents per second. Since I have to 
>>> write a few million documents, 10,000 a second is the slowest speed I can 
>>> live with. 
>>>
>>> The queues are in the /tmp folder of an AWS instance that has plenty of 
>>> disk space, 4 CPUs, and 16 gigs of RAM. 
>>>
>>> Why does the app slow down so much? I had 4 thoughts:
>>>
>>> 1.) the app struggles as it hits a memory limit
>>>
>>> 2.) memory bandwidth is the problem
>>>
>>> 3.) AWS is enforcing some weird IOPS limit
>>>
>>> 4.) durable-queue is misbehaving
>>>
>>> As to possibility #1, I notice the app starts like this:
>>>
>>> Memory in use (percentage/used/max-heap): (\"66%\" \"2373M\" \"3568M\")
>>>
>>> but 60 seconds later I see: 
>>>
>>> Memory in use (percentage/used/max-heap): (\"94%\" \"3613M\" \"3819M\")
>>>
>>> So I've run out of allowed memory. But why is that? I thought I gave 
>>> this app 7 gigs: 
>>>
>>>   :jvm-opts ["-Xms7g" "-Xmx7g" "-XX:-UseCompressedOops"])
>>>
>>> As to possibility #2, I found this old post on the Clojure mailist:
>>>
>>> Andy Fingerhut wrote, "one thing I've found in the past on a 2-core 
>>> machine that was achieving much less than 2x speedup was memory bandwidth 
>>> being the limiting factor."
>>>
>>>
>>> https://groups.google.com/forum/#!searchin/clojure/xmx$20xms$20maximum%7Csort:relevance/clojure/48W2eff3caU/HS6u547gtrAJ
>>>
>>> But I am not sure how to test this. 
>>>
>>> As to possibility #3, I'm not sure how AWS enforces its IOPS limits. If 
>>> people think this is the most likely possibility, then I will repost my 
>>> question in an AWS forum. 
>>>
>>> As to possibility #4, durable-queue is well-tested and used in a lot of 
>>> projects, and Zach Tellman is smart and makes few 

Re: possibly a Clojure question or possibly an AWS question: slow writes to durable-queue

2017-10-12 Thread lawrence . krubner
Justin Smith, thanks, I've created an Uberjar that I now run under 
Supervisord on an EC2 instance, and I set the JVM options via the command 
that Supervisord calls. 


On Wednesday, October 11, 2017 at 6:58:52 PM UTC-4, Justin Smith wrote:
>
> a small thing here, if memory usage is important you should be building 
> and running an uberjar instead of using lein on the server (this also has 
> other benefits), and if you are doing that your project.clj jvm-opts are 
> not used, you have to configure your java command line in aws instead
>
> On Wed, Oct 11, 2017 at 3:52 PM <lawrence...@gmail.com > 
> wrote:
>
>> I can't figure out if this is a Clojure question or an AWS question. And 
>> if it is a Clojure question, I can't figure out if it is more of a general 
>> JVM question, or if it is specific to some library such as durable-queue. I 
>> can redirect my question elsewhere, if people think this is an AWS 
>> question. 
>>
>> In my project.clj, I try to give my app a lot of memory:
>>
>>   :jvm-opts ["-Xms7g" "-Xmx7g" "-XX:-UseCompressedOops"])
>>
>> And the app starts off pulling data from MySQL and writing it to 
>> Durable-Queue at a rapid rate. ( https://github.com/Factual/durable-queue 
>> )
>>
>> I have some logging set up to report every 30 seconds.
>>
>> :enqueued 370137,
>>
>> 30 seconds later:
>>
>> :enqueued 608967,
>>
>> 30 seconds later: 
>>
>> :enqueued 828950,
>>
>> It's a dramatic slowdown. The app is initially writing to the queue at 
>> faster than 10,000 documents a second, but it slows steadily, and after 10 
>> minutes it writes less than 1,000 documents per second. Since I have to 
>> write a few million documents, 10,000 a second is the slowest speed I can 
>> live with. 
>>
>> The queues are in the /tmp folder of an AWS instance that has plenty of 
>> disk space, 4 CPUs, and 16 gigs of RAM. 
>>
>> Why does the app slow down so much? I had 4 thoughts:
>>
>> 1.) the app struggles as it hits a memory limit
>>
>> 2.) memory bandwidth is the problem
>>
>> 3.) AWS is enforcing some weird IOPS limit
>>
>> 4.) durable-queue is misbehaving
>>
>> As to possibility #1, I notice the app starts like this:
>>
>> Memory in use (percentage/used/max-heap): (\"66%\" \"2373M\" \"3568M\")
>>
>> but 60 seconds later I see: 
>>
>> Memory in use (percentage/used/max-heap): (\"94%\" \"3613M\" \"3819M\")
>>
>> So I've run out of allowed memory. But why is that? I thought I gave this 
>> app 7 gigs: 
>>
>>   :jvm-opts ["-Xms7g" "-Xmx7g" "-XX:-UseCompressedOops"])
>>
>> As to possibility #2, I found this old post on the Clojure mailist:
>>
>> Andy Fingerhut wrote, "one thing I've found in the past on a 2-core 
>> machine that was achieving much less than 2x speedup was memory bandwidth 
>> being the limiting factor."
>>
>>
>> https://groups.google.com/forum/#!searchin/clojure/xmx$20xms$20maximum%7Csort:relevance/clojure/48W2eff3caU/HS6u547gtrAJ
>>
>> But I am not sure how to test this. 
>>
>> As to possibility #3, I'm not sure how AWS enforces its IOPS limits. If 
>> people think this is the most likely possibility, then I will repost my 
>> question in an AWS forum. 
>>
>> As to possibility #4, durable-queue is well-tested and used in a lot of 
>> projects, and Zach Tellman is smart and makes few mistakes, so I'm doubtful 
>> that it is to blame, but I do notice that it starts off with 4 active slabs 
>> and then after 120 seconds, it is only using 1 slab. Is that expected? If 
>> people think this is the possible problem then I'll ask somewhere specific 
>> to durable-queue
>>
>> Overall, my log information looks like this: 
>>
>> ("\nStats about from-mysql-to-tables-queue: " {"message" {:num-slabs 
>> 3, :num-active-slabs 2, :enqueued 370137, :retried 0, :completed 369934, 
>> :in-progress 10}})
>>
>> ("\nResource usage: " "Memory in use (percentage/used/max-heap): 
>> (\"66%\" \"2373M\" \"3568M\")\n\nCPU usage (how-many-cpu's/load-average): 
>>  [4 5.05]\n\nFree memory in jvm: [1171310752]")
>>
>> 30 seconds later
>>
>> ("\nStats about from-mysql-to-tables-queue: " {"message" {:num-slabs 
>> 4, :num-active-slabs 4, :enqueued 608967, :retried 0, :completed 608511, 
>> :in-

Re: possibly a Clojure question or possibly an AWS question: slow writes to durable-queue

2017-10-11 Thread Daniel Compton
Without more information it's hard to tell, but this looks a like it could
be a garbage collection issue. Can you run your test again and add some
logging/monitoring to show each garbage collection? If my hunch is right,
you'll see garbage collections getting more and more frequent until they
take up nearly all the CPU time, preventing much forward progress writing
to the queue.

If it's AWS based throttling, then CloudWatch monitoring
http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/monitoring-volume-status.html#using_cloudwatch_ebs
might
show you some hints. You could also test with an NVMe drive attached, just
to see if disk bandwidth is the issue.

On Thu, Oct 12, 2017 at 11:58 AM Justin Smith <noisesm...@gmail.com> wrote:

> a small thing here, if memory usage is important you should be building
> and running an uberjar instead of using lein on the server (this also has
> other benefits), and if you are doing that your project.clj jvm-opts are
> not used, you have to configure your java command line in aws instead
>
> On Wed, Oct 11, 2017 at 3:52 PM <lawrence.krub...@gmail.com> wrote:
>
>> I can't figure out if this is a Clojure question or an AWS question. And
>> if it is a Clojure question, I can't figure out if it is more of a general
>> JVM question, or if it is specific to some library such as durable-queue. I
>> can redirect my question elsewhere, if people think this is an AWS
>> question.
>>
>> In my project.clj, I try to give my app a lot of memory:
>>
>>   :jvm-opts ["-Xms7g" "-Xmx7g" "-XX:-UseCompressedOops"])
>>
>> And the app starts off pulling data from MySQL and writing it to
>> Durable-Queue at a rapid rate. ( https://github.com/Factual/durable-queue
>> )
>>
>> I have some logging set up to report every 30 seconds.
>>
>> :enqueued 370137,
>>
>> 30 seconds later:
>>
>> :enqueued 608967,
>>
>> 30 seconds later:
>>
>> :enqueued 828950,
>>
>> It's a dramatic slowdown. The app is initially writing to the queue at
>> faster than 10,000 documents a second, but it slows steadily, and after 10
>> minutes it writes less than 1,000 documents per second. Since I have to
>> write a few million documents, 10,000 a second is the slowest speed I can
>> live with.
>>
>> The queues are in the /tmp folder of an AWS instance that has plenty of
>> disk space, 4 CPUs, and 16 gigs of RAM.
>>
>> Why does the app slow down so much? I had 4 thoughts:
>>
>> 1.) the app struggles as it hits a memory limit
>>
>> 2.) memory bandwidth is the problem
>>
>> 3.) AWS is enforcing some weird IOPS limit
>>
>> 4.) durable-queue is misbehaving
>>
>> As to possibility #1, I notice the app starts like this:
>>
>> Memory in use (percentage/used/max-heap): (\"66%\" \"2373M\" \"3568M\")
>>
>> but 60 seconds later I see:
>>
>> Memory in use (percentage/used/max-heap): (\"94%\" \"3613M\" \"3819M\")
>>
>> So I've run out of allowed memory. But why is that? I thought I gave this
>> app 7 gigs:
>>
>>   :jvm-opts ["-Xms7g" "-Xmx7g" "-XX:-UseCompressedOops"])
>>
>> As to possibility #2, I found this old post on the Clojure mailist:
>>
>> Andy Fingerhut wrote, "one thing I've found in the past on a 2-core
>> machine that was achieving much less than 2x speedup was memory bandwidth
>> being the limiting factor."
>>
>>
>> https://groups.google.com/forum/#!searchin/clojure/xmx$20xms$20maximum%7Csort:relevance/clojure/48W2eff3caU/HS6u547gtrAJ
>>
>> But I am not sure how to test this.
>>
>> As to possibility #3, I'm not sure how AWS enforces its IOPS limits. If
>> people think this is the most likely possibility, then I will repost my
>> question in an AWS forum.
>>
>> As to possibility #4, durable-queue is well-tested and used in a lot of
>> projects, and Zach Tellman is smart and makes few mistakes, so I'm doubtful
>> that it is to blame, but I do notice that it starts off with 4 active slabs
>> and then after 120 seconds, it is only using 1 slab. Is that expected? If
>> people think this is the possible problem then I'll ask somewhere specific
>> to durable-queue
>>
>> Overall, my log information looks like this:
>>
>> ("\nStats about from-mysql-to-tables-queue: " {"message" {:num-slabs
>> 3, :num-active-slabs 2, :enqueued 370137, :retried 0, :completed 369934,
>> :in-progress 10}})
>>
>> ("\nResource usage: " "Memory in

Re: possibly a Clojure question or possibly an AWS question: slow writes to durable-queue

2017-10-11 Thread Justin Smith
a small thing here, if memory usage is important you should be building and
running an uberjar instead of using lein on the server (this also has other
benefits), and if you are doing that your project.clj jvm-opts are not
used, you have to configure your java command line in aws instead

On Wed, Oct 11, 2017 at 3:52 PM <lawrence.krub...@gmail.com> wrote:

> I can't figure out if this is a Clojure question or an AWS question. And
> if it is a Clojure question, I can't figure out if it is more of a general
> JVM question, or if it is specific to some library such as durable-queue. I
> can redirect my question elsewhere, if people think this is an AWS
> question.
>
> In my project.clj, I try to give my app a lot of memory:
>
>   :jvm-opts ["-Xms7g" "-Xmx7g" "-XX:-UseCompressedOops"])
>
> And the app starts off pulling data from MySQL and writing it to
> Durable-Queue at a rapid rate. ( https://github.com/Factual/durable-queue
> )
>
> I have some logging set up to report every 30 seconds.
>
> :enqueued 370137,
>
> 30 seconds later:
>
> :enqueued 608967,
>
> 30 seconds later:
>
> :enqueued 828950,
>
> It's a dramatic slowdown. The app is initially writing to the queue at
> faster than 10,000 documents a second, but it slows steadily, and after 10
> minutes it writes less than 1,000 documents per second. Since I have to
> write a few million documents, 10,000 a second is the slowest speed I can
> live with.
>
> The queues are in the /tmp folder of an AWS instance that has plenty of
> disk space, 4 CPUs, and 16 gigs of RAM.
>
> Why does the app slow down so much? I had 4 thoughts:
>
> 1.) the app struggles as it hits a memory limit
>
> 2.) memory bandwidth is the problem
>
> 3.) AWS is enforcing some weird IOPS limit
>
> 4.) durable-queue is misbehaving
>
> As to possibility #1, I notice the app starts like this:
>
> Memory in use (percentage/used/max-heap): (\"66%\" \"2373M\" \"3568M\")
>
> but 60 seconds later I see:
>
> Memory in use (percentage/used/max-heap): (\"94%\" \"3613M\" \"3819M\")
>
> So I've run out of allowed memory. But why is that? I thought I gave this
> app 7 gigs:
>
>   :jvm-opts ["-Xms7g" "-Xmx7g" "-XX:-UseCompressedOops"])
>
> As to possibility #2, I found this old post on the Clojure mailist:
>
> Andy Fingerhut wrote, "one thing I've found in the past on a 2-core
> machine that was achieving much less than 2x speedup was memory bandwidth
> being the limiting factor."
>
>
> https://groups.google.com/forum/#!searchin/clojure/xmx$20xms$20maximum%7Csort:relevance/clojure/48W2eff3caU/HS6u547gtrAJ
>
> But I am not sure how to test this.
>
> As to possibility #3, I'm not sure how AWS enforces its IOPS limits. If
> people think this is the most likely possibility, then I will repost my
> question in an AWS forum.
>
> As to possibility #4, durable-queue is well-tested and used in a lot of
> projects, and Zach Tellman is smart and makes few mistakes, so I'm doubtful
> that it is to blame, but I do notice that it starts off with 4 active slabs
> and then after 120 seconds, it is only using 1 slab. Is that expected? If
> people think this is the possible problem then I'll ask somewhere specific
> to durable-queue
>
> Overall, my log information looks like this:
>
> ("\nStats about from-mysql-to-tables-queue: " {"message" {:num-slabs
> 3, :num-active-slabs 2, :enqueued 370137, :retried 0, :completed 369934,
> :in-progress 10}})
>
> ("\nResource usage: " "Memory in use (percentage/used/max-heap):
> (\"66%\" \"2373M\" \"3568M\")\n\nCPU usage (how-many-cpu's/load-average):
>  [4 5.05]\n\nFree memory in jvm: [1171310752]")
>
> 30 seconds later
>
> ("\nStats about from-mysql-to-tables-queue: " {"message" {:num-slabs
> 4, :num-active-slabs 4, :enqueued 608967, :retried 0, :completed 608511,
> :in-progress 10}})
>
> ("\nResource usage: " "Memory in use (percentage/used/max-heap):
> (\"76%\" \"2752M\" \"3611M\")\n\nCPU usage (how-many-cpu's/load-average):
>  [4 5.87]\n\nFree memory in jvm: [901122456]")
>
> 30 seconds later
>
> ("\nStats about from-mysql-to-tables-queue: " {"message" {:num-slabs
> 4, :num-active-slabs 3, :enqueued 828950, :retried 0, :completed 828470,
> :in-progress 10}})
>
> ("\nResource usage: " "Memory in use (percentage/used/max-heap):
> (\"94%\" \"3613M\" \"3819M\")\n\nCPU usage (how-many-cpu's/load-average)

possibly a Clojure question or possibly an AWS question: slow writes to durable-queue

2017-10-11 Thread lawrence . krubner
I can't figure out if this is a Clojure question or an AWS question. And if 
it is a Clojure question, I can't figure out if it is more of a general JVM 
question, or if it is specific to some library such as durable-queue. I can 
redirect my question elsewhere, if people think this is an AWS question. 

In my project.clj, I try to give my app a lot of memory:

  :jvm-opts ["-Xms7g" "-Xmx7g" "-XX:-UseCompressedOops"])

And the app starts off pulling data from MySQL and writing it to 
Durable-Queue at a rapid rate. ( https://github.com/Factual/durable-queue )

I have some logging set up to report every 30 seconds.

:enqueued 370137,

30 seconds later:

:enqueued 608967,

30 seconds later: 

:enqueued 828950,

It's a dramatic slowdown. The app is initially writing to the queue at 
faster than 10,000 documents a second, but it slows steadily, and after 10 
minutes it writes less than 1,000 documents per second. Since I have to 
write a few million documents, 10,000 a second is the slowest speed I can 
live with. 

The queues are in the /tmp folder of an AWS instance that has plenty of 
disk space, 4 CPUs, and 16 gigs of RAM. 

Why does the app slow down so much? I had 4 thoughts:

1.) the app struggles as it hits a memory limit

2.) memory bandwidth is the problem

3.) AWS is enforcing some weird IOPS limit

4.) durable-queue is misbehaving

As to possibility #1, I notice the app starts like this:

Memory in use (percentage/used/max-heap): (\"66%\" \"2373M\" \"3568M\")

but 60 seconds later I see: 

Memory in use (percentage/used/max-heap): (\"94%\" \"3613M\" \"3819M\")

So I've run out of allowed memory. But why is that? I thought I gave this 
app 7 gigs: 

  :jvm-opts ["-Xms7g" "-Xmx7g" "-XX:-UseCompressedOops"])

As to possibility #2, I found this old post on the Clojure mailist:

Andy Fingerhut wrote, "one thing I've found in the past on a 2-core machine 
that was achieving much less than 2x speedup was memory bandwidth being the 
limiting factor."

https://groups.google.com/forum/#!searchin/clojure/xmx$20xms$20maximum%7Csort:relevance/clojure/48W2eff3caU/HS6u547gtrAJ

But I am not sure how to test this. 

As to possibility #3, I'm not sure how AWS enforces its IOPS limits. If 
people think this is the most likely possibility, then I will repost my 
question in an AWS forum. 

As to possibility #4, durable-queue is well-tested and used in a lot of 
projects, and Zach Tellman is smart and makes few mistakes, so I'm doubtful 
that it is to blame, but I do notice that it starts off with 4 active slabs 
and then after 120 seconds, it is only using 1 slab. Is that expected? If 
people think this is the possible problem then I'll ask somewhere specific 
to durable-queue

Overall, my log information looks like this: 

("\nStats about from-mysql-to-tables-queue: " {"message" {:num-slabs 3, 
:num-active-slabs 2, :enqueued 370137, :retried 0, :completed 369934, 
:in-progress 10}})

("\nResource usage: " "Memory in use (percentage/used/max-heap): 
(\"66%\" \"2373M\" \"3568M\")\n\nCPU usage (how-many-cpu's/load-average): 
 [4 5.05]\n\nFree memory in jvm: [1171310752]")

30 seconds later

("\nStats about from-mysql-to-tables-queue: " {"message" {:num-slabs 4, 
:num-active-slabs 4, :enqueued 608967, :retried 0, :completed 608511, 
:in-progress 10}})

("\nResource usage: " "Memory in use (percentage/used/max-heap): 
(\"76%\" \"2752M\" \"3611M\")\n\nCPU usage (how-many-cpu's/load-average): 
 [4 5.87]\n\nFree memory in jvm: [901122456]")

30 seconds later

("\nStats about from-mysql-to-tables-queue: " {"message" {:num-slabs 4, 
:num-active-slabs 3, :enqueued 828950, :retried 0, :completed 828470, 
:in-progress 10}})

("\nResource usage: " "Memory in use (percentage/used/max-heap): 
(\"94%\" \"3613M\" \"3819M\")\n\nCPU usage (how-many-cpu's/load-average): 
 [4 6.5]\n\nFree memory in jvm: [216459664]")

30 seconds later

("\nStats about from-mysql-to-tables-queue: " {"message" {:num-slabs 1, 
:num-active-slabs 1, :enqueued 1051974, :retried 0, :completed 1051974, 
:in-progress 0}})


-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Joy of Clojure question

2014-05-14 Thread Gary Johnson
Bridget and Guru are both right about the reason that \3 is found at 
position 13 in the string. However, the code you typed isn't valid Clojure, 
since the pos function expects pred to be a function of v. Thus, your pos 
call would need to look like this:

(pos #(= % \3) :a 4 :b 1 :c 3 :d 4) = (13)  ;; note that pos returns a 
list of all indeces matching pred

Alternatively, you could have defined pos to simply perform equality 
matching on its first argument like so:

(defn pos [val coll]
  (for [[i v] (index coll) :when (= val v)] i))

(pos \3 :a 4 :b 1 :c 3 :d 4) = (13)

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Joy of Clojure question

2014-05-14 Thread kurofune
Haha, right on Gary! I used the later version of the original function, but 
the earlier call to the original function. Here is what it looked like in 
the beginning. This was an example of how not to write a function that 
looks up indices by value.  The example code I posted above was the 
supposed better way. 

(defn pos [e coll]
   (let [cmp (if (map? coll)
   #(= (second %1) %2)
   #(= %1 %2))]
 (loop [s coll idx 0]
   (when (seq s)
 (if (cmp (first s) e)
   (if (map? coll)
 (first (first s))
 idx)
   (recur (next s) (inc idx)))




On Thursday, May 15, 2014 1:31:34 AM UTC+9, Gary Johnson wrote:

 Bridget and Guru are both right about the reason that \3 is found at 
 position 13 in the string. However, the code you typed isn't valid Clojure, 
 since the pos function expects pred to be a function of v. Thus, your pos 
 call would need to look like this:

 (pos #(= % \3) :a 4 :b 1 :c 3 :d 4) = (13)  ;; note that pos returns a 
 list of all indeces matching pred

 Alternatively, you could have defined pos to simply perform equality 
 matching on its first argument like so:

 (defn pos [val coll]
   (for [[i v] (index coll) :when (= val v)] i))

 (pos \3 :a 4 :b 1 :c 3 :d 4) = (13)


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Joy of Clojure question

2014-05-13 Thread gamma235
I am reading The Joy of Clojure now and am finishing chapter 5 on sequence 
abstractions. There is an example given that demonstrates how to locate the 
index of an element in a sequence by value, but I don't understand why the 
character lookup here is returning 13. Can somebody please explain this to 
me?

(defn index [coll]
   (cond
(map? coll) (seq coll)
(set? coll) (map vector coll coll)
:else (map vector (iterate inc 0) coll)))

 (defn pos [pred coll]
   (for [[i v] (index coll) :when (pred v)] i))

 

 (pos \3 :a 4 :b 1 :c 3 :d 4)   

 

= 13


J 

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Joy of Clojure question

2014-05-13 Thread Bridget
\3 is a character literal, so you're looking up the character 3. You're 
looking it up in a collection which is a string. Count from the first 
position, 0, a colon, then 1, the letter a, and so on. 3 is at the 13th 
position.

On Tuesday, May 13, 2014 9:44:38 PM UTC-4, gamma235 wrote:

 I am reading The Joy of Clojure now and am finishing chapter 5 on sequence 
 abstractions. There is an example given that demonstrates how to locate the 
 index of an element in a sequence by value, but I don't understand why the 
 character lookup here is returning 13. Can somebody please explain this to 
 me?

 (defn index [coll]
   (cond
(map? coll) (seq coll)
(set? coll) (map vector coll coll)
:else (map vector (iterate inc 0) coll)))

 (defn pos [pred coll]
   (for [[i v] (index coll) :when (pred v)] i))

  

 (pos \3 :a 4 :b 1 :c 3 :d 4)   

  

 = 13


 J 


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Joy of Clojure question

2014-05-13 Thread Guru Devanla
The call to (index) returns this vector

([0 \:] [1 \a] [2 \space] [3 \4] [4 \space] [5 \:] [6 \b] [7 \space] [8 \1]
[9 \space] [10 \:] [11 \c] [12 \space] [13 \3] [14 \space] [15 \:] [16 \d]
[17 \space] [18 \4])

And, 3 here is in the 13th position. Your (cond) in index function is
picking up the :else branch.


On Tue, May 13, 2014 at 6:44 PM, gamma235 jesus.diama...@gmail.com wrote:

 I am reading The Joy of Clojure now and am finishing chapter 5 on sequence
 abstractions. There is an example given that demonstrates how to locate the
 index of an element in a sequence by value, but I don't understand why the
 character lookup here is returning 13. Can somebody please explain this to
 me?

 (defn index [coll]
   (cond
(map? coll) (seq coll)
(set? coll) (map vector coll coll)
:else (map vector (iterate inc 0) coll)))

 (defn pos [pred coll]
   (for [[i v] (index coll) :when (pred v)] i))



 (pos \3 :a 4 :b 1 :c 3 :d 4)



 = 13


 J

 --
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clojure@googlegroups.com
 Note that posts from new members are moderated - please be patient with
 your first post.
 To unsubscribe from this group, send email to
 clojure+unsubscr...@googlegroups.com
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+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 Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Joy of Clojure question

2014-05-13 Thread gamma235
Okay, both these answers make lots of sense. thank you for your help. 

J

On Wednesday, May 14, 2014 11:47:51 AM UTC+9, Guru Devanla wrote:

 The call to (index) returns this vector 

 ([0 \:] [1 \a] [2 \space] [3 \4] [4 \space] [5 \:] [6 \b] [7 \space] [8 
 \1] [9 \space] [10 \:] [11 \c] [12 \space] [13 \3] [14 \space] [15 \:] [16 
 \d] [17 \space] [18 \4])

 And, 3 here is in the 13th position. Your (cond) in index function is 
 picking up the :else branch.


 On Tue, May 13, 2014 at 6:44 PM, gamma235 jesus.d...@gmail.comjavascript:
  wrote:

 I am reading The Joy of Clojure now and am finishing chapter 5 on 
 sequence abstractions. There is an example given that demonstrates how to 
 locate the index of an element in a sequence by value, but I don't 
 understand why the character lookup here is returning 13. Can somebody 
 please explain this to me?

 (defn index [coll]
   (cond
(map? coll) (seq coll)
(set? coll) (map vector coll coll)
:else (map vector (iterate inc 0) coll)))

 (defn pos [pred coll]
   (for [[i v] (index coll) :when (pred v)] i))

  

 (pos \3 :a 4 :b 1 :c 3 :d 4)   

  

 = 13


 J 

 -- 
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clo...@googlegroups.comjavascript:
 Note that posts from new members are moderated - please be patient with 
 your first post.
 To unsubscribe from this group, send email to
 clojure+u...@googlegroups.com javascript:
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 --- 
 You received this message because you are subscribed to the Google Groups 
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an 
 email to clojure+u...@googlegroups.com javascript:.
 For more options, visit https://groups.google.com/d/optout.




-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Clojure question

2013-04-18 Thread Phillip Lord

ng...@students.rowan.edu writes:
 Hello, I'm doing a school paper on Clojure but there are two questions that 
 i just can't find answers to anywhere they are:


 Are data types bound to variables and parameters at compile-time? run-time? a 
 combination?

 and also,

 How are parameters passed? (Pass by value? Pass by reference? Pass by 
 value-result? etc.)

 If anybody knows the answers to these two questions I would greatly 
 appreciate it! 


If you can't find the answers to these questions anywhere, you either
have not looked, or don't understand the questions. Either way, you will
learn nothing from the answers you are getting. 

You probably wouldn't be able to tell the difference between a correct
answer and one which is just a wind-up. Which category do you think
Marko's answer comes into?

Phil

-- 
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.




Clojure question

2013-04-17 Thread ngm24
 

Hello, I'm doing a school paper on Clojure but there are two questions that 
i just can't find answers to anywhere they are:


Are data types bound to variables and parameters at compile-time? run-time? a 
combination?

and also,

How are parameters passed? (Pass by value? Pass by reference? Pass by 
value-result? etc.)

If anybody knows the answers to these two questions I would greatly appreciate 
it! 

-Matt
 

-- 
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.




Re: Clojure question

2013-04-17 Thread Marko Topolnik


 Are data types bound to variables and parameters at compile-time? run-time? a 
 combination?


Clojure, like LISPs in general, is primarily a dynamically-typed language, 
so variables/parameters don't have a type assigned to them. However, on JVM 
Clojure there are optional type hints, which constrain the type at compile 
time.
 


 How are parameters passed? (Pass by value? Pass by reference? Pass by 
 value-result? etc.)


Clojure inherits the argument-passing semantics from Java. So it is 
pass-by-value, where the value passed is an object reference. In addition 
there are optimization facilities that enable the passing of 
primitive-typed values.
 
-marko



-- 
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.




PCL - Clojure: question about variables

2011-11-07 Thread Matthew Giannini
I am new to Clojure and have been working through some of the examples
on the PCL - Clojure blog.  Currently I am working through Chapter 6
(variables).

The blog says Nothing stops multiple functions from closing on the
same variables. Here is a function that returns an incrementer,
decrementer, and accessor, all sharing the same counter:

  (defn counters []
(let [count (ref 0)]
  (list #(dosync (alter count inc))
  #(dosync (alter count dec))
  #(deref count

I tried to this example (with Clojure 1.3.0 and 1.2.1) and found that
it does not appear to work, or I am totally missing something.  Here
is some output from a REPL session using this function.  Could you
help me understand the output or, if there is a mistake in the
example, could you explain what it is?

Question 1: I expected these two statements to produce output 1, 2
user= ((nth (counters) 0))
1
user= ((nth (counters) 0))
1

Question 2: So then I did the following:

user= (def a (nth (counters) 0))
#'user/a
user= (def b (nth (counters) 2))
#'user/b
user= (a)
1
user= (a)
2
user= (a)
3
user= (b)
0

Now the incrementer appears to be working, but then when I try to use
the accessor to inspect the value of count, it is still 0.  So it
appears that the 3 anonymous functions in the list are not closing
over count.

Could somebody help me understand this behavior? Thank you for your
help.

matthew





-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: PCL - Clojure: question about variables

2011-11-07 Thread Meikel Brandmeyer (kotarak)
Hi,

with each call to counters you get new incrementers, decrementers and 
accessors referecing different counters underneath. Capture the return 
value of the counters call.

(def fns (counters))
((nth fns 0))
((nth fns 0))
((nth fns 2))

Hope this helps.

Sincerely
Meikel

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

beginner clojure question: OutOfMemory error processing (slightly) large data file

2011-03-22 Thread Avram
Hi,

I (still) consider myself new to clojure.  I am trying to read a 37Mb
file that will grow 500k every 2 days. I don't consider this to be
input large enough file to merit using Hadoop and I'd like to process
it in Clojure in an efficient, speedy, and idiomatic way.

I simply want something akin to a transpose, where the input looks
like this:
( [ a1 b1 c1 d1 ] [ a2 b2 c2 d2 ] [ a3 b3 c3 d3 ])

…and the output looks like this:

[ [ a1 a2 a3 ] [ b1 b2 b3 ] [ c1 c2 c3 ] [ d1 d2 d3 ] ]

Gleaning what I can from various sources and cobbling them together, I
have the following below, which works for small input but not for the
intended file sizes (and larger) I'd like it to be able to handle.

(use 'clojure.contrib.io)
(require 'clojure.string)

(def tabfn /Users/avram/data/testdata.tab)

(defn is-comment?
Checks if argument is a comment (i.e. starts with a '#').
   Returns: boolean.
  [line]
  (= \# (first line)))

(defn data-lines
Returns data lines in file (i.e. all lines that do not start with
'#')
  Returns: sequence containing data lines
[filename]
(drop-while is-comment? (line-seq (reader filename

(defn parsed-data-lines
  [filename]
  (map #(clojure.string/split % #\t) (data-lines filename)))

(def signals (vec (apply map vector (parsed-data-lines tabfn


user= (def signals (vec (apply map vector (parsed-data-lines
tabfn
java.lang.OutOfMemoryError: Java heap space (NO_SOURCE_FILE:68)


How can I avoid the OutOfMemoryError?

Is there a Leiningen setting where I can increase the memory or is
there a more efficient way to achieve this?

Also, I'd prefer to read in gzip'd tab-delimited files instead of
uncompressed tab-delimited files.  What is the idiomatic clojure way
to do this?


Comments on improvements and criticisms welcome :)

Thanks,
Avram

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: beginner clojure question: OutOfMemory error processing (slightly) large data file

2011-03-22 Thread Ken Wesson
On Tue, Mar 22, 2011 at 4:00 PM, Avram aav...@me.com wrote:
 Hi,

 I (still) consider myself new to clojure.  I am trying to read a 37Mb
 file that will grow 500k every 2 days. I don't consider this to be
 input large enough file to merit using Hadoop and I'd like to process
 it in Clojure in an efficient, speedy, and idiomatic way.

 I simply want something akin to a transpose, where the input looks
 like this:
 ( [ a1 b1 c1 d1 ] [ a2 b2 c2 d2 ] [ a3 b3 c3 d3 ])

 …and the output looks like this:

 [ [ a1 a2 a3 ] [ b1 b2 b3 ] [ c1 c2 c3 ] [ d1 d2 d3 ] ]

 Gleaning what I can from various sources and cobbling them together, I
 have the following below, which works for small input but not for the
 intended file sizes (and larger) I'd like it to be able to handle.

You'll need to avoid holding onto the head of your line-seq, which
means you'll need to make multiple passes over the data, one for the
as, one for the bs, and etc., with the output a lazy seq of lazy seqs.

 (defn data-lines
    Returns data lines in file (i.e. all lines that do not start with
 '#')
      Returns: sequence containing data lines
    [filename]
    (drop-while is-comment? (line-seq (reader filename

The description doesn't match the function, unless it's guaranteed
that no line will start with # after the first line that doesn't do
so. You may want remove instead of drop-while here, or to change the
doc string.

 Also, I'd prefer to read in gzip'd tab-delimited files instead of
 uncompressed tab-delimited files.  What is the idiomatic clojure way
 to do this?

There are zip functions in the Java standard library. I don't know if
they can handle gzip, or just pkzip. In the worst case, you'd have no
library you could use. Even then, it could be done in at least two
ways.

1. Use Runtime/exec to call shell tools to gunzip the file to a
   temporary file for processing.

2. Read at wikipedia and implement gunzip in Clojure, using byte arrays
   and whatever other tools you'd need to work with binary data at a low
   level, and/or Java's ByteBuffer and related classes.

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: beginner clojure question: OutOfMemory error processing (slightly) large data file

2011-03-22 Thread Stuart Sierra
Hi Avram,

Assuming you're using the Sun/Oracle JDK, you can increase the size of the 
Java heap with the -Xmx command-line option.  For example:

java -Xmx512mb -cp clojure.jar:your-source-dir clojure.main

Will run Java with a 512 MB heap.  This increases the amount of memory 
available to your program.  Obviously, you don't want the heap to be larger 
than the available RAM.

With Leiningen, you can add the :jvm-opts option in project.clj, as shown 
here: 
https://github.com/technomancy/leiningen/blob/master/sample.project.clj#L142

More generally, this line:

(def signals (vec ...))

says that you want the entire result, as a vector, stored as the value of 
the Var `signals`.  That means your entire result data must fit in the Java 
heap.  For a 37 MB file, that's not unreasonable, but as soon as your file 
gets larger than your available RAM, you'll have to come up with an 
alternate approach.

-Stuart Sierra
clojure.com

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: beginner clojure question: OutOfMemory error processing (slightly) large data file

2011-03-22 Thread Stuart Sierra
Oh, and the standard JDK class java.util.zip.GZIPInputStream implements gzip 
decompression.

-Stuart Sierra
clojure.com

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: beginner clojure question: OutOfMemory error processing (slightly) large data file

2011-03-22 Thread Avram
Thanks, Stuart.

 With Leiningen, you can add the :jvm-opts option in project.clj,

Cool, this is what I was looking for :)


     (def signals (vec ...))

 says that you want the entire result, as a vector, stored as the value of
 the Var `signals`.  That means your entire result data must fit in the Java
 heap.  

Yes, this is what I want.  I suppose that if it grows too large, I can
figure out a way to write it to a file somehow instead of creating a
vector.  The end result will likely be a JSON representation for each
of the signals a, b, c, and d written to a file.

~A

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Swing Java example to Clojure - Question about better translation

2009-04-23 Thread Dimiter malkia Stanev

Hello,

I've started dabbling into Swing  Clojure, and for fun decided to
translate one of the Sun examples (requires Java SE 1.6 though)

It's located here:
   
http://java.sun.com/docs/books/tutorial/uiswing/examples/learn/index.html#CelsiusConverter

and the java code here:
  
http://java.sun.com/docs/books/tutorial/uiswing/examples/learn/CelsiusConverterProject/src/learn/CelsiusConverterGUI.java

I've translated the above java code to clojure here:
  http://paste.lisp.org/display/79061


But I feel I did not do good job on it. The hard part was this
convention of creating object inline, and calling it's method to
further add elements/extend the system. It reminds of TurboVision from
the glory TurboPascal days:

  layout.setHorizontalGroup(
layout.createParallelGroup
(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup
(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
. // more code omitted
.addContainerGap(27, Short.MAX_VALUE))
);

I've did my best:

(doto layout
  (.setHorizontalGroup
   (.. layout (createParallelGroup GroupLayout$Alignment/LEADING)
   (addGroup
(.. layout (createSequentialGroup)
(addContainerGap)
(addGroup
 (.. layout (createParallelGroup GroupLayout$Alignment/LEADING)
 (addGroup
 ;; more code omitted
  (addComponentfahrenheit-label)
(addContainerGap 27 Short/MAX_VALUE)

But I feel I can do it better (some fancy macro?). Any ideas how I can
improve it.

I understand from the Java comments that the layout code was
autogenerated by a tool, but still it's an interresting question.

Granted the .. sugary macro helped a lot, but my brain melted a bit
while I was translating it :)




Here is the full code, in case the paste.lisp.org doesn't work:

(import '(javax.swing JFrame JLabel JTextField JButton GroupLayout
GroupLayout$Alignment SwingConstants LayoutStyle LayoutStyle
$ComponentPlacement)
'(java.awt.event ActionListener)
'(java.awt Component))

(defn celsius-converter-gui
  Translation of the simple Celsius Converter GUI Swing Example from
Java to Clojure (requires Java SE 1.6)
   
http://java.sun.com/docs/books/tutorial/uiswing/examples/learn/CelsiusConverterProject/src/learn/CelsiusConverterGUI.java;
  []
  (let [frame(new JFrame Celsius Converter)
pane (. frame getContentPane)
layout   (new GroupLayout pane)
temp-text-field  (new JTextField)
celsius-label(new JLabel Celsius)
convert-button   (new JButton Convert)
fahrenheit-label (new JLabel Fahrenheit)]
(. convert-button addActionListener
   (proxy [ActionListener] []
 (actionPerformed [event]
  (. fahrenheit-label setText
 (str (+ 32.0
 (* 1.8
(Double/parseDouble
 (. temp-text-field getText
   Fahrenheit)
(doto layout
  (.setHorizontalGroup
   (.. layout (createParallelGroup GroupLayout$Alignment/LEADING)
   (addGroup
(.. layout (createSequentialGroup)
(addContainerGap)
(addGroup
 (.. layout (createParallelGroup GroupLayout$Alignment/LEADING)
 (addGroup
  (.. layout (createSequentialGroup)
  (addComponenttemp-text-field
   GroupLayout/PREFERRED_SIZE
   GroupLayout/DEFAULT_SIZE
   GroupLayout/PREFERRED_SIZE)
  (addPreferredGap 
LayoutStyle$ComponentPlacement/RELATED)
  (addComponentcelsius-label)))
 (addGroup
  (.. layout (createSequentialGroup)
  (addComponentconvert-button)
  (addPreferredGap 
LayoutStyle$ComponentPlacement/RELATED)
  (addComponentfahrenheit-label)
(addContainerGap 27 Short/MAX_VALUE)
  (.linkSize SwingConstants/HORIZONTAL
 (into-array Component [convert-button temp-text-field]))
  (.setVerticalGroup
   (.. layout (createParallelGroup GroupLayout$Alignment/LEADING)
   (addGroup
(.. layout (createSequentialGroup)
(addContainerGap)
(addGroup
 (.. layout (createParallelGroup GroupLayout$Alignment/BASELINE)
 

Re: Having struggle in understanding FP (and Clojure question)

2008-11-07 Thread Graham Fawcett

On Fri, Nov 7, 2008 at 12:25 AM, cwyang [EMAIL PROTECTED] wrote:

 My expectation is these:
 1) For C10K problem (or C100K), application must not use
 native threads. Big stack size means low concurrency

Hi,

I assume you mean 'new native thread per request' is bad for CnK.
Clojure's thread-pooling is not very different from the N:M threading
model that Erlang-OTP/Yaws uses, in a general sense.

 4) At the same time, there must be ways for connecting conceptual
 gap between 2) and 3). In other words, the way for suspending current
 execution of function, saving current execution snapshot
 (normally native thread stack, but may be different),
 and switching to other functions are needed when the request for I/O
 should be blocked. It's important that the size of current execution
 snapshot should be small, since it determine the degree of
 concurrency.

Sounds like you're looking for first-class continuations here.You
won't find that on any JVM language, there's no JVM support for them.
(It is true that JVM-based Scheme languages have continuations, but
they are severely limited by the constraints of the JVM).

If you really believe you need this, you might be interested in
Termite, an Erlang-style actor system written for Gambit Scheme (which
has serializable first-class continuations and very lightweight
threads, but no SMP support if I remember correctly).

An alternative would be to use non-blocking I/O multiplexing -- an
event-driven model like you would write with select() or epoll(). I
don't know the Java universe very well, but I know JVM has
asynchronous I/O, so this must be an available option. Writing such
programs can sometimes lead to hard-to-understand, fragmented
application code, but Clojure's flexible syntax might be able to help
unify the fragments into a more readable form.

Best,
Graham

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Having struggle in understanding FP (and Clojure question)

2008-11-06 Thread Konrad Hinsen

On 05.11.2008, at 17:16, Mark H. wrote:

 and replace copies with destructive writes.  I haven't seen a purely
 functional formulation of LU factorization but it could be done
 without too much trouble.  Of course there's no reason to go through
 that effort because people spend so much time optimizing LU and its
 constituent components that you would be better off reusing their
 work.

For the immediate future, yes. But with changing computer  
architectures, the existing algorithms and routines may lose much of  
their interest in the future.

 To me the more interesting and rewarding task is to figure out how to
 splice existing HPC libraries into a functional framework, without
 losing the ability to reason functionally about the components.

Unfortunately, it is already a bit of a pain to link existing HPC  
libraries (written in Fortran, C, or C++) to functional code in any  
decent language. Clojure won't help there, as there are still very  
few HPC libraries for the JVM and JNI adds too much of an overhead.

 Definitely!  We've got at least one fellow here who uses Common Lisp
 to generate stencil codes.  He's been thinking about switching to
 Clojure ever since he and I worked on a thorny Lisp problem
 together ;-)

I am looking forward to a nice Clojure library then :-)

Konrad.


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Having struggle in understanding FP (and Clojure question)

2008-11-06 Thread cwyang

Thanks everyone.

I've read all the replies, and I might understand something.
(Though it seems that discussion goes to beyond my current
understanding in the middle of this discussion threads)
To explore further, I become another owner of 'Programming
Clojure' :-)

For my second question, I'll keep thinking and repost question.
I'm really concern about concurrency of Clojure,
since the concurrency in my world means
_the C10K problem_, that is supporting simultaneous
1 connections or over for networking applications.
(http://www.kegel.com/c10k.html)
In YAWS, Erlang have shown one solution, so I'm curios that
Clojure could be another viable alternative,
and that how well-suited Clojure is for that kind of concurrency.

My expectation is these:
1) For C10K problem (or C100K), application must not use
native threads. Big stack size means low concurrency
2) For application developer, thread model is easy to develop
and follow.
3) Therefore, underlying system should support
concurrency facility like micro-thread, lightweight process (in
Erlang)
, agent (in Clojure), or whatever.
In this case, underlying facility should have high-performance.
4) At the same time, there must be ways for connecting conceptual
gap between 2) and 3). In other words, the way for suspending current
execution of function, saving current execution snapshot
(normally native thread stack, but may be different),
and switching to other functions are needed when the request for I/O
should be blocked. It's important that the size of current execution
snapshot should be small, since it determine the degree of
concurrency.

After I invest some time to learn Clojure, I'll repost.

Thank you.

- cw
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Having struggle in understanding FP (and Clojure question)

2008-11-06 Thread Mark H.

On Nov 6, 11:58 am, Konrad Hinsen [EMAIL PROTECTED] wrote:
 On 05.11.2008, at 17:16, Mark H. wrote:
 For the immediate future, yes. But with changing computer  
 architectures, the existing algorithms and routines may lose much of  
 their interest in the future.

Haha, yes, we're working on this ;-)  (a number of my colleagues are,
at least).

  To me the more interesting and rewarding task is to figure out how to
  splice existing HPC libraries into a functional framework, without
  losing the ability to reason functionally about the components.

 Unfortunately, it is already a bit of a pain to link existing HPC  
 libraries (written in Fortran, C, or C++) to functional code in any  
 decent language. Clojure won't help there, as there are still very  
 few HPC libraries for the JVM and JNI adds too much of an overhead.

Does the JNI require copy-in / copy-out for arrays of floating-point
numbers?  I know Java has messed-up floating-point (Sun stupidly took
away x87's 80-bit temps and other good things) but I'd at least like
to avoid copy overhead for matrix and vector ops.  I don't mind the
extra function call out of JVM space as long as I can amortize it over
the cost of a big matrix operation.  (No way I'm writing loops in
Clojure for that.)

There are a number of Python-based projects to do what you mentioned
(link HPC libraries in Fortran or C to a higher-level language), so
it's not impossible.  It's just a lot of tedious work for some unlucky
coders.

  Definitely!  We've got at least one fellow here who uses Common Lisp
  to generate stencil codes.  He's been thinking about switching to
  Clojure ever since he and I worked on a thorny Lisp problem
  together ;-)

 I am looking forward to a nice Clojure library then :-)

We'll see -- he's got it working in CL now and he's got a deadline, so
he may not bother migrating it.  Plus he likes the ECL / C linkup;
Java may not be so helpful for him.

mfh


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Having struggle in understanding FP (and Clojure question)

2008-11-05 Thread mb

Hi,

On 5 Nov., 08:31, Konrad Hinsen [EMAIL PROTECTED] wrote:
 That's exactly my point. Multimethods may well be sufficient or even  
 superior for implementing OO concepts useful in Clojure. We will see  
 when someone actually uses them this way (or has it already  
 happened?). But as long as the most important interfaces (sequences,  
 maps, numbers), which happen to be the ones also used by the built-in  
 types, don't use the same mechanism, there will always be first-class  
 and second-class citizens in Clojure's datatype universe.

I don't think that there are first-class and second-class citizens.
They
just have a different aspect. Having pure Clojure classes with
multimethods might well be integrated and nice, but you get problems
when you have to interface to Java. On the other hand using Java
classes gives you easy interface, but you have to live with gen-class.
So which one is first, which one second class? I think each solution
has just different Pros and Cons.

What would interesting, is the question, whether both approaches
could be combined. We make a Java class (via gen-class), which
gets a default implementation for each method, which references
a similar named multimethod instead of the Class-methodName.
Clojure classes deriving from that class do not provide an
a Java method themselves, but register with the multimethod.
The Clojure code could use the multimethods, while there are still
the methods available for a Java interface. So the downside would
be that one can only inherit from one such prototype class (since
it needs to be a class, not an interface, for the default
implementation
of the methods) or one has to respecify the method - multimethod
translation in all sub classes. Maybe a modified gen-class could
support?

(These are just random thoughts. Maybe they make sense, maybe
not.)

For the built-in datatypes: I implemented nth and get as multimethods
(as some kind of proof-of-concept), but Rich was not very interested
due to performance issues and the fact, that the datatypes are used
internally in very low-level areas. I don't really follow the argument
about monkey patching. I think it's not monkey patching at all, since
the multimethods only define the interface. So I don't modify a thing
which is returned by hash-map. That's still a hash map using the
hash-map implementation.

- http://clojure-log.n01se.net/date/2008-10-06.html#13:18

Sincerely
Meikel


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Having struggle in understanding FP (and Clojure question)

2008-11-05 Thread Konrad Hinsen

On Nov 5, 2008, at 11:12, mb wrote:

 I don't think that there are first-class and second-class citizens.
 They just have a different aspect.

Right, one can't say one is superior to the other. There are just two  
separate worlds, each having its own characteristics.

 Having pure Clojure classes with
 multimethods might well be integrated and nice, but you get problems
 when you have to interface to Java. On the other hand using Java
 classes gives you easy interface, but you have to live with gen-class.

But does gen-class have to look the way it does? Couldn't the same  
functionality be provided in a way that looks more like a proper part  
of the language?

 What would interesting, is the question, whether both approaches
 could be combined. We make a Java class (via gen-class), which
 gets a default implementation for each method, which references
 a similar named multimethod instead of the Class-methodName.

That sounds like an interesting idea.

 For the built-in datatypes: I implemented nth and get as multimethods
 (as some kind of proof-of-concept), but Rich was not very interested
 due to performance issues and the fact, that the datatypes are used
 internally in very low-level areas.

I can understand performance arguments, of course. And I don't really  
want to modify the built-in types in any way, I just want to be able  
to use the same interfaces in completely independent datatype  
implementations.

The current implementation of nth provides a special implementation  
for each kind of datatype that it knows about, and fails for unknown  
types. Shouldn't it be possible to add a default case at the end that  
calls a Clojure multimethod? That shouldn't have any performance  
impact on the built-in datatypes.

 I don't really follow the argument about monkey patching. I think  
 it's not monkey patching at all, since
 the multimethods only define the interface.

I agree. It's no more monkey-patching than any use of multimethods  
would be monkey-patching.

Konrad.




--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Having struggle in understanding FP (and Clojure question)

2008-11-05 Thread mb

Hi,

On 5 Nov., 15:40, Konrad Hinsen [EMAIL PROTECTED] wrote:
 But does gen-class have to look the way it does? Couldn't the same  
 functionality be provided in a way that looks more like a proper part  
 of the language?

I'm not sure about the form itself. I had look at a CLOS tutorial
and that defclass doesn't look to different in the form the function
is called, a mix of keywords and arguments.

My main concern with gen-class is that it doesn't use the namespace
itself. I posted a patch[1] yesterday which addresses the namespace
and -/_ translation. I rose this also some weeks ago on the list but
there was no response. So the general interest seems to be pretty
low. On the other hand Rich, seems to have something like this on
his TODO list[2]. But maybe everything is different again because
of AOT. So I'm not sure, what his plans are for gen-class right now.

[1]: 
http://groups.google.com/group/clojure/browse_thread/thread/386d90a8b757aee4
[2]: http://richhickey.backpackit.com/pub/1597914

 The current implementation of nth provides a special implementation  
 for each kind of datatype that it knows about, and fails for unknown  
 types. Shouldn't it be possible to add a default case at the end that  
 calls a Clojure multimethod? That shouldn't have any performance  
 impact on the built-in datatypes.

That is a good idea. It would be really cool.

Sincerely
Meikel


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Having struggle in understanding FP (and Clojure question)

2008-11-05 Thread Mark H.

On Nov 4, 11:46 pm, Konrad Hinsen [EMAIL PROTECTED] wrote:
  Long answer:  SISAL is an example of a functional parallel language

 Ah, right, there was SISAL... unfortunately long forgotten.

I saw a retrospective presentation on it at SIAM PP this spring by one
of the Livermore folks who promoted it.  Pretty neat!

  One could express solving linear systems (which is what I presume you
  mean by matrix inversion, unless you really want the entries of the
  inverse) in a purely functional way using a language like SISAL with a
  compiler that optimizes away temporaries, and the resulting

 Could one? That was actually the core of my question. Of course HPC  
 applications would require smart compilers that, but first of all  
 there must be a purely functional algorithm that can be transformed  
 automatically into an efficient one. Do you know any references to  
 such algorithms in linear algebra?

There's probably a big difference between in theory and in
practice in this case ;-)  SISAL didn't have multidimensional arrays
so I doubt very much that it could have optimized away the creation of
matrix temporaries.

The usual trick to make things look functional is to index vector
variables with the current iteration, so that you aren't overwriting
anything.  Then if the compiler can prove that there are no read-after-
write conflicts, it can collapse the vector variables into one vector
and replace copies with destructive writes.  I haven't seen a purely
functional formulation of LU factorization but it could be done
without too much trouble.  Of course there's no reason to go through
that effort because people spend so much time optimizing LU and its
constituent components that you would be better off reusing their
work.

 Of course, HPC applications dealing with large data sets would always  
 want algorithms that modify matrices in place instead of allocating  
 more memory. I don't expect a purely OO HPC world any time soon. But  
 it would still be interesting to know how many of the traditional CPU-
 hungry algorithms already have known efficient functional equivalents.

To me the more interesting and rewarding task is to figure out how to
splice existing HPC libraries into a functional framework, without
losing the ability to reason functionally about the components.

 Me too. HPC is only one aspect of my work. And I think languages like  
 Clojure can be useful for generating specialized HPC code as well,  
 just like FFTW uses Caml code for generating C routines.

Definitely!  We've got at least one fellow here who uses Common Lisp
to generate stencil codes.  He's been thinking about switching to
Clojure ever since he and I worked on a thorny Lisp problem
together ;-)

mfh
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Having struggle in understanding FP (and Clojure question)

2008-11-04 Thread Randall R Schulz

On Tuesday 04 November 2008 06:03, Konrad Hinsen wrote:
 ...

 As an illustration of the two approaches, consider a program to sort
 data. In OOP, one would define an abstract class comparable with a
 method sort that works by calling methods such as greater and
 equal implemented in concrete subclasses. In FP, one would write a
 function sort that takes as arguments a list of things to sort plus
 a function to do the comparisons. At the top level of the program,
 you'd see interface comparable in the OOP version and function
 sort in the FP version. A mixed OOP-FP program might call the FP
 function sort and pass the method compare of a subclass of
 comparable as the comparison function.

Even the current Java libraries and object model belie this comparison. 
An array of intrisically comparable instances (those that implement 
Comparable) can be sorted without supplying a Comparator. But an array 
of arbitrary Objects can be sorted in arbitrary and flexible ways by 
supplying a Comparable that accepts the types submitted to it.


 Konrad.


Randall Schulz

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Having struggle in understanding FP (and Clojure question)

2008-11-04 Thread Konrad Hinsen

On Nov 4, 2008, at 15:20, mb wrote:

 And as an effect of not forcing the sorting logic into some class,
 one can easily sort the same data in different ways in the FP style.
 While implementing an interface Comparable defines *one* way
 of sorting, the FP style separates the functions from the data. So
 it is eg. easily possible to sort a list of email objects by subject,
 author or date, or any combination thereof.

Sorting is indeed an example where the FP approach is superior. But  
then, it is not representative in size and complexity of a typical  
program or library. One could easily cite other examples where OOP  
would be the better choice. My ideal language would support both as  
much as possible.

An example of where Clojure lacks OO features, in my opinion, is your  
lazy-map library. It provides an additional implementation for an  
existing interface, which is a typical OO approach, and a very useful  
one. But although all your code is written Clojure, it looks like a  
kludge in having to use a feature (genclass) intended for Java  
compatibility and forcing an unnatural file structure (one file for  
the methods, one for the code generation, and one for the end-user  
wrapper) on the implementation.

Konrad.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Having struggle in understanding FP (and Clojure question)

2008-11-04 Thread Konrad Hinsen

On Nov 4, 2008, at 3:44, cwyang wrote:

 So, I understand as follows:
 - OOP: keeping objects, which has states and methods.
methods are encapuslated to the corresponding object.
 - FP: keeping objects(or structs or variables, whatever it is called)
   and functions on the objects.
   functions does not encapsulated to specific objects, for some
 reasons.

 Other characteristics such as function as first-order data structure
 and
 enforcing functional way (discourated side effects and immutable
 variables)
 can be important, but not in modeling the world.

I think the difference is more fundamental than what you describe. On  
the other hand, I don't think that OOP and FP are contradictory.

Here is my view of things:

OOP = data abstraction. The program structure is defined by the data  
that the program works on. Important data structures are identified  
and implemented together with their associated operations as classes.

FP = algorithmic abstraction. The program structure is defined by the  
algorithms that are used. Important algorithmic patterns are  
identified and implemented as functions that take functional  
arguments, or as macros. Functional arguments make it possible to  
insert specific actions into a skeleton.

There are additional properties typically associated with OOP  
(polymorphism, inheritance, ...) and FP (referential transparency,  
immutable data structures, ...), but I think the approch to program  
structure is the aspect where the two methods differ most. On the  
other hand, there is no reason not to use both data abstraction and  
algorithmic abstraction in a program. In that sense OOP and FP are  
orthogonal and combinable.

As an illustration of the two approaches, consider a program to sort  
data. In OOP, one would define an abstract class comparable with a  
method sort that works by calling methods such as greater and  
equal implemented in concrete subclasses. In FP, one would write a  
function sort that takes as arguments a list of things to sort plus  
a function to do the comparisons. At the top level of the program,  
you'd see interface comparable in the OOP version and function  
sort in the FP version. A mixed OOP-FP program might call the FP  
function sort and pass the method compare of a subclass of  
comparable as the comparison function.

Konrad.



--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Having struggle in understanding FP (and Clojure question)

2008-11-04 Thread Konrad Hinsen

On Nov 4, 2008, at 17:26, Mark H. wrote:

 Of course sometimes you need side effects in order to accomplish
 useful work, and a good FP language will provide abstractions that
 help you limit side effects and reason about them.  Clojure does this
 by means of refs, agents, and transactional updates.  refs are
 different than regular values so that you know they are mutable.

Vars are also mutable, even if that mutability is local to a thread.  
I guess one could write state-modifying code in Clojure just like in  
most imperative languages, it is merely discouraged and made hard to  
hide. That looks like a very reasonable compromise to me.

 An object-oriented program may also use FP.  OOP and FP are not
 opposites.  However, a lot of OO programming these days involves
 changing the state of opaque objects (therefore, not purely
 functional) via member functions.  I've heard this characterized as
 the new spaghetti code because it's hard to reason about thread-
 safety when objects are being modified all the time, and when these
 modifications aren't syntactically obvious.

Even in the absence of threads, changing state can be a cause of  
trouble, in particular if it is well hidden under a few layers of  
nice-looking APIs.

On the other hand, I am not sure that all important algorithms  
already have purely functional equivalents that are sufficiently  
efficient for real life. Is there an efficient purely functional  
algorithm for matrix inversion, for example?

Konrad.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Having struggle in understanding FP (and Clojure question)

2008-11-04 Thread Meikel Brandmeyer

Hi,

Am 04.11.2008 um 16:06 schrieb Konrad Hinsen:

An example of where Clojure lacks OO features, in my opinion, is your
lazy-map library. It provides an additional implementation for an
existing interface, which is a typical OO approach, and a very useful
one. But although all your code is written Clojure, it looks like a
kludge in having to use a feature (genclass) intended for Java
compatibility and forcing an unnatural file structure (one file for
the methods, one for the code generation, and one for the end-user
wrapper) on the implementation.

I disagree. Clojure brings everything needed: multimethods. One defines
a set of multimethods (the interface) and different arguments may have
different implementations.

Inheritance can also be replaced with delegation without problems. And
in fact lazy-map does not inherit from any maptype. Instead it delegates
to another instance without caring for whether it's a struct map, hash
map or sorted map. With inheritance each of this types would have needed
an own lazy-x-map class. This is again some style of functional OO
programming.

Suppose get, contains?, etc. were multimethods. I would not have needed
gen-class. I just would register my own implementations for the lazy- 
map.

But the problem is: Clojure's map interface is not implemented with
multimethods. They have a Java side. If I want to provide a drop-in
replacement I have to also serve that side. Hence I need gen-class.
Or Java itself for that matter in case gen-class is too kludgy.

I don't think that Clojure is that bad for object-oriented programming.
It just looks a bit different than usual.

Sincerely
Meikel



smime.p7s
Description: S/MIME cryptographic signature


Re: Having struggle in understanding FP (and Clojure question)

2008-11-04 Thread Mark H.

On Nov 4, 10:01 am, Konrad Hinsen [EMAIL PROTECTED] wrote:
 On the other hand, I am not sure that all important algorithms  
 already have purely functional equivalents that are sufficiently  
 efficient for real life. Is there an efficient purely functional  
 algorithm for matrix inversion, for example?

Short answer:  No ;-)

Long answer:  SISAL is an example of a functional parallel language
designed for performance.  Its compiler could optimize away
temporaries in purely functional code (the equivalent of loop/recur).
Optimizing away temporaries (esp. temp vectors and submatrices turns
out to be important for several reasons:

* Parallel GC is scary (not impossible, though)
* Memory usage is tight for big problems
* A lot of HPC code is limited by memory bandwidth so creating
temporary vectors (for example) rather than overwriting existing ones
is slow

One could express solving linear systems (which is what I presume you
mean by matrix inversion, unless you really want the entries of the
inverse) in a purely functional way using a language like SISAL with a
compiler that optimizes away temporaries, and the resulting
implementation may very well be highly efficient.  Krylov methods like
conjugate gradient for sparse linear systems would be even easier for
the compiler to optimize since they don't modify the matrix, only
vectors.

HPC coders tend to resist functional implementations because

* they like to control memory allocation themselves
* the existing code infrastructure is not functional
* for cultural reasons

That was basically why SISAL didn't take off at Livermore.  HPC coders
do, however, write a lot of control code, scripts, etc. that can
benefit from FP.  This is why I follow Clojure (for example).

mfh

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Having struggle in understanding FP (and Clojure question)

2008-11-04 Thread Konrad Hinsen

On 04.11.2008, at 19:08, Meikel Brandmeyer wrote:

 Suppose get, contains?, etc. were multimethods. I would not have  
 needed
 gen-class. I just would register my own implementations for the  
 lazy-map.
 But the problem is: Clojure's map interface is not implemented with
 multimethods. They have a Java side.

That's exactly my point. Multimethods may well be sufficient or even  
superior for implementing OO concepts useful in Clojure. We will see  
when someone actually uses them this way (or has it already  
happened?). But as long as the most important interfaces (sequences,  
maps, numbers), which happen to be the ones also used by the built-in  
types, don't use the same mechanism, there will always be first-class  
and second-class citizens in Clojure's datatype universe.

Konrad.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Having struggle in understanding FP (and Clojure question)

2008-11-04 Thread Konrad Hinsen

On 04.11.2008, at 20:07, Mark H. wrote:

 Long answer:  SISAL is an example of a functional parallel language

Ah, right, there was SISAL... unfortunately long forgotten.

 One could express solving linear systems (which is what I presume you
 mean by matrix inversion, unless you really want the entries of the
 inverse) in a purely functional way using a language like SISAL with a
 compiler that optimizes away temporaries, and the resulting

Could one? That was actually the core of my question. Of course HPC  
applications would require smart compilers that, but first of all  
there must be a purely functional algorithm that can be transformed  
automatically into an efficient one. Do you know any references to  
such algorithms in linear algebra?

Of course, HPC applications dealing with large data sets would always  
want algorithms that modify matrices in place instead of allocating  
more memory. I don't expect a purely OO HPC world any time soon. But  
it would still be interesting to know how many of the traditional CPU- 
hungry algorithms already have known efficient functional equivalents.

 That was basically why SISAL didn't take off at Livermore.  HPC coders
 do, however, write a lot of control code, scripts, etc. that can
 benefit from FP.  This is why I follow Clojure (for example).

Me too. HPC is only one aspect of my work. And I think languages like  
Clojure can be useful for generating specialized HPC code as well,  
just like FFTW uses Caml code for generating C routines.

Konrad.


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



newb slime/clojure question...

2008-11-03 Thread Peter Hart

I've been trying to get clojure working with slime (on windows). I can
run ants.clj from the command line fine. I can run simple expressions
under slime (e.g. (+ 2 3)). However, when I try to run ants.clj from
within slime, I get the following warning in the inferior lisp buffer,
and nothing happens.

Reflection warning, line: 280 - call to drawImage can't be resolved.
Reflection warning, line: 283 - call to setPreferredSize can't be
resolved.

Looking at the sun.boot.class.path property for both executables seems
the same. When I look at the system classpath using the invocation I
found here: http://paste.lisp.org/display/69257 I get the clojure.jar,
and ~/.clojure/*. From the command line directly, I just get
clojure.jar on the classpath.

Anybody have any advice on how I can fix this?


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---