Hello
I noticed that compiling fails (Nim 1.06) with {.passC: "-Werror -pedantic".} i.e. when I follow my C habit to be stringent with code and ask gcc to treat warnings as errors also in the Nim generated code. It seems the culprit is stdlib_system.nim.c.
Error 1 error: ISO C forbids conversion of object pointer to function pointer type [-Werror=pedantic] ((Finalizer) ((*t).finalizer))(T5_);
Error 2 In function ‘sysFatal__... error: ‘noreturn’ function does return
Error 3 same as 2 but another sysFatal__... where '...' stands for what looks like a hash
The other problem (mine) is about wrapping some C code.
Situation: I've written a Nim wrapper for (yet another) fast but good quality (non-cs) random generator. When running the C test version I achieve (-march=x86-64 -mtune=nehalem on a Zen1 Ryzen) a bit above 3 GB of random bytes per second. When running test nim (using my wrapper) it's about 1 GB/s slower. Losing about 30% performance is of course not something that makes me happy.
My suspicion is that it's my mistake and that NIM copies the state object and/or the result array on each call.
Explanation: I have to pass in a state object which is but two uint32 arrays.
type PState* = ref object
x: array[8, uint32]
y: array[4, uint32]
in my prng_wrap.nim along with type PResult* = array[32, uint8] and proc prand(s: PState) : ptr byte {.importc.} ## The C core proc Note: My wrapper calling this proc prand casts the result to PResult (return cast[PResult](s.x))
Which I create in test.nim var ps = new(PState) and (var) pr: PResult and then call pr = prand(ps) 32 million times (exactly as I do in the C version) it works fine but is about 30% slower.
Now a) I'm confident that Nim's overhead is far less than 30% and b) I have been forced to work in C and Ada for some months and certainly forgot some of the finer points in dealing with and passing pointers (and refs), so I guess it's my fault. Any idea where my mistake is and how to bring the Nim version to something like 95+% of the C version speed?
Thanks in advance (oh, and congrats and thanks a ton and another ton for Nim 1.x! I'm immensely pleased by that)
-Werror Is not useful for nim generated code. Warnings are for humans not compiler output. Nim compiler will do a ton of unsafe things in C because they are actually safe in nim. No one is going to spend time fixing auto generated warnings... thats not what warnings are for! See: https://forum.nim-lang.org/t/5785
"about 1 GB/s slower" - Its our favorite pastime to beat C code at speed. No seriously not sarcastic! Post minimal version of your code please and we will make it fast... Did you compile -d:realse or -d:danger? You probably can't pass ref object`s to C and it should probably be `ptr object? I don't think nim is copying your objects, but it might be your code. Post it!
Hmm, frankly, I'm not satisfied by the "it's just warnings" answer as we are not talking about "variable declared but unused" bla bla. But I'll leave it at that because my point isn't about creating a fuzz. I know for a fact that some warnings should be taken seriously and that it's no matter of human vs. machine created. But if the Nim tell me that I need not worry I accept that.
As for my problem: thanks but I need no optimization help. The C code (which is the core) has already been optimized. My problem, I'm pretty sure of that, is some mistake I made. It seems highly likely that Nim copies either the state or the result instead of just an address.
I would be grateful if someone with Nim - C interface experience could provide a meaningful hint where I made a mistake.
Thanks
I need no optimization help.
But you ask exactly for this -- for help optimizing the C -- Nim interface.
You know C well, and in the Nim cache directory there is all the C code visible, so you could invest it. I don't think that even the brightest Nim devs can just guess the problem. Investigating your code is impossible as long you do not provide it, and even when you provide it, investigation is some boring task. For your pass by ref vs pass by value, Nim generally passes larger objects by ref, I think objects smaller than the size of 3 floats is passed by value. But of course there can be a hidden bug. treeform told you already that generally you can not pass Nim ref objects, as that are owned by Nim GC.
Sorry, I meant the prng itself. Also while I understand that one might read it as an optimization it actually was a question where I made an error that led to "anti-optimization".
Well, whatever, I went the cumbersome path and found my suspicion confirmed. cast[PResult](s.x) had Nim copy the content (32 bytes) rather than simply changing a uint32 pointer to a uint8 pointer. Meanwhile I have changed my wrapper and achieve about 99% of the speed of the C version.
Btw, all the relevant information was provided but it was of course easier to ask me for my source and to tell me that I should solve my problem myself.
regards
https://github.com/nim-lang/Nim/pull/11591 is merged you'll be able to show c/c++ warnings (see that PR for rationale + bugs it helped uncover)
Thanks. In fact I doubt the proposition that warnings are only for humans. For example stating "noreturn" but actually returning should be considered as at least questionable. Sure, one can do a lot of trickery but I have learned (the hard way) that good code is clean code and I would never deliver code that doesn't pass -Wall -Werror -pedantic. In fact I often even use good quality static analyzers too. But again, I'm not looking for trouble and won't insist. It's just that I had high hopes re. Nim and seeing Ada mentioned as a major influence was one of the factors that drove me to Nim. And don't get me wrong, I still think that Nim is a great language, it just seems to be less safety obsessed than I expected. On the other hand I understand that that's maybe something for later and that Araq first wanted to get it feature complete and to 1.0.
Thank you also for calming my initial worries that this community has gotten less friendly and helpful than I remember it. Have a nice weekend!
found my suspicion confirmed. castPResult had Nim copy the content (32 bytes) rather than simply
Great. It would be nice if you could push minimal example code for that behaviour to Nim issue tracker, it may be a bug. I personally avoid casts myself, but I would not assume it generation a copy.
Note also that you may have to use -d:danger and -d:release at the same time for maximum speed. -d:danger should include -d:release, but recently it did not, there was a forum post and soon a fix.