0

UPDATE

To better clarify, my question is not if I'm doing the code right or not, I've already understood after the profiling that I wasn't.

The question is: Are you supposed to observe SBCL taking 100%CPU after running a program no matter what you did good or bad? And, is this something that you guys have seen happening before? - I.e. a known bug?

I'd give a reproducible example if I could, but this CPU hogging only happens sometimes (and I've never used multithreading constructs anywhere).

Sorry for not being more clear the first time around :)

-----

Bug?

I'm having occasional issues with Lisp using 100% CPU for long periods of time after running programs.

Update: Right now it was using 100% CPU for 40 minutes after the program had finished computation.

Environment: SBCL, rowswell, emacs+SLIME

My question is if this is a known bug in Common Lisp that I'm not aware of and might be related to GC?

Context

It's not the first time that it happens "randomly", but it has happened that more computationally heavy programs that do a lot of memory allocation end up using 100% for a long time (40min in this case) after the program finished.

The routine is single-threaded, thus there's no possibility of some task still running in the background.

I don't believe it's normal for SBCL to spend 40min after a program runs using 100% CPU. I'm afraid this might be related to some bug in GC?

I then profiled the program in SLIME:

enter image description here

and the program was super slow (~20min execution) and did a lot of allocations, then changed one line, and it now takes 2s to run, just because I was always formatting a debug string to an empty stream (thus generating new string representations of a list with 100k integers at each call):

enter image description here

(https://github.com/AlbertoEAF/advent_of_code_2019/commit/b37797df772c12c2d409b1c3356cf5b690c8f928)

That is not my point though. Even though this case is extremely ill-posed, the task I'm doing is very simple, and thus the program I'm using is irrelevant, the concern is the unstability of the platform, in scenarios where one is using sustained heavy computation and allocation. Are there reports of any issues like this with SLIME/SBCL or some other thing I'm not aware of?

Thank you!

5
  • 2
    I can't comment on the threading part, but from the profile output compute-op-output and compute are apparently consing a lot and taking a lot of time. You may want to focus on optimizing those functions. Also, is there perhaps a data structure that keeps growing in memory? Commented Apr 11, 2020 at 9:36
  • 2
    Please don't post images of the screen: they are within epsilon of useless. If you want people to say things about the code post the code. If you want people to say things about the output from the profiler post output from the profiler; if you want people to be able to see the output from top, post that. As a friend of mine once used to say 'cut and paste is enabled'. See how to ask. Commented Apr 11, 2020 at 10:11
  • "the concern is the unstability of the platform, if using sustained heavy computation and allocation": the platform is stable, since it eventually returned a result despite heavy computation and allocation during 40 minutes. Commented Apr 14, 2020 at 8:00
  • Maybe I didn't explain well, but the program itself took 20min, the thing is that it then spent 40 min after the program ran, using 100% CPU, which doesn't seem ok, does that make sense? Commented Apr 14, 2020 at 11:05
  • This question is not reproducible. The rules of stack overflow state that you must provide a minimal, complete, reproducible description of your problem. Some ideas: you’re having multi threading/locking issues; you use too much memory and start swapping; you’re program is trying to print some massive object (maybe with pretty printing and print-circle); you are building a profile in ram and slowly writing it to disk/analysing it once your code has run. Commented Apr 14, 2020 at 20:16

1 Answer 1

2

The reason your change improves performance is that debug-stream is NIL.

In the old code you evaluate:

(format nil ...) 

When you give nil as the stream to format, it prints to a string so you are doing the formatting work and allocating a big string you throw away.

In the new code you do:

(when nil ...) 

Which costs approximately 0.

Note that nil does not mean do nothing when you pass it to format. In general if you want to do nothing you should do nothing instead of calling functions that do things.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.