<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Cgo on Roberto Selbach</title><link>https://rselbach.com/tags/cgo/</link><description>Recent content in Cgo on Roberto Selbach</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Wed, 29 Aug 2012 18:45:00 +0000</lastBuildDate><atom:link href="https://rselbach.com/tags/cgo/index.xml" rel="self" type="application/rss+xml"/><item><title>Batching calls across cgo</title><link>https://rselbach.com/batching-calls-across-cgo/</link><pubDate>Wed, 29 Aug 2012 18:45:00 +0000</pubDate><guid>https://rselbach.com/batching-calls-across-cgo/</guid><description>&lt;p&gt;I wrapped a C checksum function and called it once per 32-byte record. The C loop won its isolated benchmark, yet the complete program lost. I had measured the work and ignored the doorway.&lt;/p&gt;
&lt;p&gt;The fix was not exotic:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// One crossing for the whole buffer.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sum&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;C&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;checksum&lt;/span&gt;((&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;C&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;uchar&lt;/span&gt;)(&lt;span style="color:#a6e22e"&gt;unsafe&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Pointer&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;buf&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;])), &lt;span style="color:#a6e22e"&gt;C&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;size_t&lt;/span&gt;(len(&lt;span style="color:#a6e22e"&gt;buf&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I benchmarked batches of 1, 16, 256, and 4096 records from the same input. On my machine the one-record version managed about 7 MB/s; batches of 16 reached 58 MB/s, 256 reached 170 MB/s, and 4096 changed little at 174 MB/s. These are not portable constants. The flattening was the useful result: by 256 records, the checksum was work again and the bridge was no longer the benchmark.&lt;/p&gt;
&lt;p&gt;I also timed the pure Go checksum in the same harness. It reached 112 MB/s. That made the decision less silly: either stay in Go and keep the simple boundary, or batch enough for C&amp;rsquo;s faster loop to pay its admission fee. Calling C per record was the one clearly bad option.&lt;/p&gt;
&lt;p&gt;The batch API takes a contiguous buffer plus record metadata and returns all checksums at once. It also makes ownership easy to state: the buffer remains valid during the call, and C retains no Go pointer afterward.&lt;/p&gt;
&lt;p&gt;The caveat is the empty slice: &lt;code&gt;&amp;amp;buf[0]&lt;/code&gt; is invalid when &lt;code&gt;len(buf) == 0&lt;/code&gt;, so real code checks length first. C memory needs C lifetime rules, callbacks need even more care, and a blocking C call affects runtime scheduling differently from an ordinary Go function.&lt;/p&gt;
&lt;p&gt;I picked 256 records because larger batches bought almost nothing and delayed results. The benchmark supplied both halves of that choice; “fewer cgo calls” by itself would have pushed the batch size toward absurdity.&lt;/p&gt;</description></item><item><title>errno and strings at the cgo border</title><link>https://rselbach.com/errno-and-strings-at-the-cgo-border/</link><pubDate>Wed, 20 Jul 2011 19:10:00 +0000</pubDate><guid>https://rselbach.com/errno-and-strings-at-the-cgo-border/</guid><description>&lt;p&gt;I wrapped a C function that opens a file. The call itself was easy; deciding where a C string stopped and a Go &lt;code&gt;os.Error&lt;/code&gt; began took the rest of the afternoon.&lt;/p&gt;
&lt;p&gt;The first useful program was deliberately dull:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;package&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include &amp;lt;fcntl.h&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include &amp;lt;stdlib.h&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;static int open_read_only(const char *name) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;	return open(name, O_RDONLY);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#e6db74"&gt;&amp;#34;os&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#e6db74"&gt;&amp;#34;unsafe&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;open&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;) (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;os&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;cname&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;C&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;CString&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;defer&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;C&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;free&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;unsafe&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Pointer&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;cname&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;fd&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;C&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;open_read_only&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;cname&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fd&lt;/span&gt; &amp;lt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; int(&lt;span style="color:#a6e22e"&gt;fd&lt;/span&gt;), &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The comment immediately before &lt;code&gt;import &amp;quot;C&amp;quot;&lt;/code&gt; is cgo&amp;rsquo;s preamble, not decoration. The little C wrapper is necessary because &lt;code&gt;open&lt;/code&gt; is variadic and cgo cannot call it directly. &lt;code&gt;C.CString&lt;/code&gt; allocates and copies, so the matching &lt;code&gt;C.free&lt;/code&gt; stays next to it. The Go string may contain a zero byte, too; a C API will see that as the end of the name. My wrapper rejects such names before this call rather than quietly opening something else.&lt;/p&gt;
&lt;p&gt;In a two-result cgo call, cgo captures C&amp;rsquo;s &lt;code&gt;errno&lt;/code&gt; as the &lt;code&gt;os.Error&lt;/code&gt; used by this Go snapshot. I test the function&amp;rsquo;s documented failure result first; a stale nonzero &lt;code&gt;errno&lt;/code&gt; after a successful call is not an error. This also keeps C&amp;rsquo;s zero-terminated error text on the C side of the wrapper rather than exposing a borrowed character pointer to callers.&lt;/p&gt;
&lt;p&gt;That translation belongs right here. Returning a bare integer status would make every caller know C&amp;rsquo;s failure sentinel, when &lt;code&gt;errno&lt;/code&gt; is meaningful, and how long the message storage lives. One wrapper is enough bureaucracy.&lt;/p&gt;
&lt;p&gt;There are wrinkles beyond this toy. Some functions return errors directly instead of using &lt;code&gt;errno&lt;/code&gt;; some return allocated strings that need a library-specific free function; and a successful result can still require cleanup. The C header, not habit, decides each case.&lt;/p&gt;
&lt;p&gt;There are practical caveats. The build now needs a C compiler and the library&amp;rsquo;s headers and linker flags. Types that merely look alike are not automatically interchangeable. Memory allocated by C must be released according to C&amp;rsquo;s rules, and Go pointers should not be tucked away by C code for later use.&lt;/p&gt;
&lt;p&gt;The wrapper is dull now: Go string in, file descriptor or &lt;code&gt;os.Error&lt;/code&gt; out. Dull borders are much easier to debug.&lt;/p&gt;</description></item><item><title>cgo Is a Border, Not a Bridge</title><link>https://rselbach.com/cgo-is-a-border-not-a-bridge/</link><pubDate>Fri, 11 Jun 2010 20:52:00 +0000</pubDate><guid>https://rselbach.com/cgo-is-a-border-not-a-bridge/</guid><description>&lt;p&gt;I have too much useful C code to pretend a new language arrives on an empty disk. My first serious Go experiment therefore needed an old image-processing library. That led directly to cgo, then to several hours learning that a foreign-function interface is a border crossing, not a transparent bridge.&lt;/p&gt;
&lt;p&gt;The smallest call is almost suspiciously simple. In the snapshot I used, a preamble before &lt;code&gt;import &amp;quot;C&amp;quot;&lt;/code&gt; declares the C side:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;package&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;scale&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include &amp;lt;stdint.h&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;static uint32_t clamp(uint32_t v, uint32_t limit) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; return v &amp;lt; limit ? v : limit;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;C&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;clamp&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;v&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;limit&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;uint32&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;uint32&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; uint32(&lt;span style="color:#a6e22e"&gt;C&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;clamp&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;C&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;uint32_t&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;v&lt;/span&gt;), &lt;span style="color:#a6e22e"&gt;C&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;uint32_t&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;limit&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The exact generated names and build steps are tied to this weekly release. cgo is changing quickly, so this is a field note rather than a durable manual. I run cgo as part of the package build, compile its generated C, then let the normal architecture-specific tools finish the package.&lt;/p&gt;
&lt;p&gt;Scalar conversion is the easy part. Buffers force the real questions: who owns the memory, how long does an address remain valid, and may either runtime retain it after the call? I settled on a strict rule for this experiment: Go calls C synchronously, C consumes the supplied bytes before returning, and C stores no pointer into Go-managed memory.&lt;/p&gt;
&lt;p&gt;For output allocated by the C library, I expose a C release function and call it with &lt;code&gt;defer&lt;/code&gt; immediately after checking the returned pointer. That keeps allocation and release in the same ownership domain. Wrapping a C allocation in a Go slice may avoid a copy, but it also makes lifetime assumptions much easier to hide. I copy unless profiling proves the copy matters.&lt;/p&gt;
&lt;p&gt;Strings are another ownership test disguised as convenience. A Go string is not a NUL-terminated C string. Conversion may allocate. Embedded zero bytes have C semantics whether I find them philosophically agreeable or not. Passing length explicitly is better whenever the C API permits it.&lt;/p&gt;
&lt;p&gt;Then I measured the crossing. I called a trivial C function in a loop and compared it with the same arithmetic written in Go. The absolute figures are not worth publishing because both cgo and the compiler are moving, but the shape was obvious: crossing for every pixel was disastrous; crossing once per image was lost in the actual work.&lt;/p&gt;
&lt;p&gt;That changed my wrapper. The first version exposed the C library nearly function for function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Go pixel loop -&amp;gt; cgo -&amp;gt; C operation -&amp;gt; return
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The revised version sends a whole row or image:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Go request -&amp;gt; cgo -&amp;gt; C loop over image -&amp;gt; return
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The second interface is less “complete” and much more useful. It minimizes transitions and expresses the operation at the level where ownership is clear.&lt;/p&gt;
&lt;p&gt;Callbacks in the other direction are harder. They combine scheduler state, foreign threads, and object lifetime. I avoided them by collecting results in C and returning a batch. That is not always possible, but it is a better starting point than assuming a C callback can enter arbitrary Go code safely. The runtime is young and its constraints deserve respect, not exploratory production outages.&lt;/p&gt;
&lt;p&gt;Failures need translation too. The C library reports integer status codes and sometimes leaves detail in a structure. My wrapper converts those into a small Go value implementing the snapshot&amp;rsquo;s &lt;code&gt;os.Error&lt;/code&gt; convention. I do not leak C constants throughout callers. If the library returns a partial result, the wrapper states whether that result remains valid and who frees it.&lt;/p&gt;
&lt;p&gt;The build is the least elegant part. Header search paths, linker flags, and platform differences have not vanished; they have merely moved to the package boundary. This is still better than spreading them through the program, but cgo does not make a C dependency portable by blessing it with a comment.&lt;/p&gt;
&lt;p&gt;I keep one integration test that allocates, calls, copies, releases, and repeats. It catches ownership regressions more reliably than staring harder at the wrapper.&lt;/p&gt;
&lt;p&gt;My conclusion is deliberately conservative. cgo is excellent for preserving a tested, substantial C implementation. It is poor as a shortcut for tiny functions that cross the boundary constantly. Design a coarse interface, keep ownership explicit, translate failures once, and benchmark the complete operation. A border can support trade. It should not run through the middle of the kitchen.&lt;/p&gt;</description></item></channel></rss>