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