Small @nogc experience report
Meta
jared771 at gmail.com
Fri Sep 7 17:01:09 UTC 2018
On Friday, 7 September 2018 at 16:44:05 UTC, Peter Alexander
wrote:
> I recently wrote a small program of ~600 lines of code to solve
> an optimisation puzzle. Profiling showed that GC allocations
> were using non-trivial CPU, so I decided to try and apply @nogc
> to remove allocations. This is a small experience report of my
> efforts.
>
> 1. My program does some initialisation before the main solver.
> I don't care about allocations in the initialisation. Since not
> all of my code needed to be @nogc, I couldn't add `@nogc:` to
> the top of the file and instead had to refactor my code into
> initialisation parts and main loop parts and wrap the latter in
> @nogc { ... }. This wasn't a major issue, but inconvenient.
>
> 2. For my code the errors were quite good. I was immediately
> able to see where GC allocations were occurring and fix them.
>
> 3. It was really frustrating that I had to make the compiler
> happy before I was able to run anything again. Due to point #1
> I had to move code around to restructure things and wanted to
> make sure everything continued working before all GC
> allocations were removed.
>
> 4. I used std.algorithm.topNCopy, which is not @nogc. The error
> just says "cannot call non- at nogc function [...]". I know there
> are efforts to make Phobos more @nogc friendly, but seeing this
> error is like hitting a brick wall. I wouldn't expect topNCopy
> to use GC, but as a user, what do I do with the error? Having
> to dig into Phobos source is unpleasant. Should I file a bug?
> What if it is intentionally not @nogc for some subtle reason?
> Do I rewrite topNCopy?
Semi-unrelated, but I think you should open a bug for this one. I
remember Andrei stating before that every function in
std.algorithm except for LevehnsteinDistance(?) is @nogc, so he
either missed topNCopy or the gc-ness of the function has changed
sometime between ~2015 and now.
Actually, thanks to the fact that run.dlang.io provides the
ability to compile a code snippet with all compilers since 2.060,
this is very easy to debug:
import std.algorithm;
import std.range;
void main()
{
int[100] store;
auto nums = iota(100);
nums.topNCopy(store[]); //compiles
}
Now if I add @nogc to main:
Up to 2.060 : Failure with output: onlineapp.d(4): Error:
valid attribute identifiers are @property, @safe, @trusted,
@system, @disable not @nogc
2.061 to 2.065.0: Failure with output: onlineapp.d(4): Error:
undefined identifier nogc
2.066.0: Failure with output: onlineapp.d(8): Error: @nogc
function 'D main' cannot call non- at nogc function
'std.algorithm.topNCopy!("a < b", Result, int[]).topNCopy'
2.067.1 to 2.078.1: Failure with output: onlineapp.d(8): Error:
@nogc function 'D main' cannot call non- at nogc function
'std.algorithm.sorting.topNCopy!("a < b", Result, int[]).topNCopy'
Since 2.079.1: Failure with output: onlineapp.d(8): Error:
`@nogc` function `D main` cannot call non- at nogc function
`std.algorithm.sorting.topNCopy!("a < b", Result, int[]).topNCopy`
So it seems that it's never worked. Looking at the
implementation, it uses a std.container.BinaryHeap, so it'd
require a small rewrite to work with @nogc.
> 5. Sometimes I wanted to add writeln to my code to debug
> things, but writeln is not @nogc, so I could not. I could have
> used printf in hindsight, but was too frustrated to continue.
You are allowed to call "@gc" functions inside @nogc functions if
you prefix them with a debug statement, e.g.:
void main() @nogc
{
debug topNCopy(source, target);
}
You then have to pass the appropriate switch to the compiler to
tell it to compile in the debug code.
> 6. In general, peppering my code with @nogc annotations was
> just unpleasant.
>
> 7. In the end I just gave up and used -vgc flag, which worked
> great. I had to ignore allocations from initialisation, but
> that was easy. It might be nice to have some sort of `ReportGC`
> RAII struct to scope when -vgc reports the GC.
I've been thinking lately that @nogc may have been going to far,
and -vgc was all that was actually needed. -vgc gives you the
freedom to remove or ignore GC allocations as necessary, instead
of @nogc's all or nothing approach.
More information about the Digitalmars-d
mailing list