August 26, 2015

OSCON 2015: Impressions

Posted in Software at 04:19 by graham

I attended OSCON for the first time this year in Portland. This was a dream come true for me, I have wanted to attend for many years. Here are my impressions and some talk links. I can’t link you to most of the talks, because O’Reilly sells them for $1,000. Open Source indeed.

First, it is a very big conference. They had 1,200 talk proposals, 4,700 attendees, up to 13 talks running concurrently, and two competing mobile apps. Twice I walked into a random Portland bar, which turned out to be hosting an OSCON-related event. It’s that big.

Second, it is a strange mixture of open-source and commercialism. Sponsors above a certain level get a keynote. Tremendous efforts are expended to herd the attendees into the expo hall at every opportunity, towards the paying booths. And I can’t link you to the best talks, because as mentioned O’Reilly sells them. On the other hand all sorts of people I admire in the tech world were there, and I had some wonderful conversations with them, and at the booths in the open-source section. At OSCON, you get to be a peer of the people who’s blogs and books you read, and that’s really special.

Here are the speaker slides, a youtube search and, of the public ones, my favorites:

See you next year, in Austin!

July 31, 2015

GopherCon 2015: Favorite talks

Posted in Software at 04:58 by graham

GopherCon was in Denver again this year, and a lot of fun it was, mostly the meeting of wonderful people. Judging by the sponsors, Go continues to be the language of infrastructure (docker, coreos, etcd, mesos, kubernetes, influxdb, etc). Here are my three favorite talks:

  • Rick Hudson: Go GC: Latency problem solved. This was probably the highlight of the conference for me. Rick is a fun speaker, and he’s talking about the key feature in Go 1.5. The garbage collector used to freeze your application for increasingly large amounts of time as you used more memory. It no longer does.
  • Dmitry Vyukov: Go Dynamic Tools. Dmitry covers three tools: The race detector, go-fuzz, and the new execution tracer. The Go tooling is amazing.
  • Audrey Lim: A Beginner’s Mind. Audrey is a lawyer who became a programmer recently, and she recounts her journey – but wait, read on. I confess when her talk was announced I thought I would not find it interesting. I was very wrong, because Audrey is phenomenal. She tried Python, Ruby and Node JS first, and detailed exactly why those were hard for a complete beginner. She made some very astute observations about how the language you use shapes how you think about programming, and the projects you will undertake.

Here are all the other GopherCon 2015 videos.

Robert Griesemer’s keynote highlighted the Pascal (via Oberon) heritage of Go, and remarked that Pascal is a European language family. The C heritage of Go that is more commonly referenced is North American. He hoped Go is a merging of the two software cultures.

And finally, joke of the conference has to go to Tomás Senart.

July 24, 2015

Building shared libraries in Go: Part 2

Posted in Software at 22:12 by graham

In part 1 we called a very simple Go shared library from Python. Let’s do a more complex example, passing string and []byte, from C++, and getting back a []byte.

Calling Go from C++

Save the following as concat/main.go:

package main

import "C"

//export Concat
func Concat(sIn string, bIn []byte, bOut []byte) {
    n := copy(bOut, sIn)
    copy(bOut[n:], bIn)
}

func main() {}

We add the import "C" so that cgo gives us a header file to #include. Build the shared library and header:

go build -buildmode=c-shared -o libconcat.so concat

In libconcat.h we have this signature:

extern void Concat(GoString p0, GoSlice p1, GoSlice p2)

GoString and GoSlice are defined further up in the header file like this:

typedef struct { char *p; GoInt n; } GoString;
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;

Copy libconcat.so to /usr/lib/ (or wherever your libraries live). Now let’s call Concat from C++:

#include <vector>
#include <string>
#include <iostream>
#include "libconcat.h"

int main() {
    std::string s_in {"Hello "};
    std::vector<char> v_in {'W', 'o', 'r', 'l', 'd'};
    std::vector<char> v_out(11);

    GoString go_s_in{&s_in[0], static_cast<GoInt>(s_in.size())};
    GoSlice go_v_in{
        v_in.data(),
        static_cast<GoInt>(v_in.size()),
        static_cast<GoInt>(v_in.size()),
    };
    GoSlice go_v_out{
        v_out.data(),
        static_cast<GoInt>(v_out.size()),
        static_cast<GoInt>(v_out.size()),
    };

    Concat(go_s_in, go_v_in, go_v_out);

    for(auto& c : v_out) {
        std::cout << c;
    }
    std::cout << '\n';
}

Save that as concat.cpp. Copy libconcat.h into the same directory. Build and run:

g++ --std=c++14 concat.cpp -o concat -lconcat
./concat

I need the static_cast<GoInt> because a GoInt is a signed type (long long on my machine), but size() returns unsigned type size_t. Apart from wrapping things in Go[String|Slice|etc], this is exactly like calling an ordinary shared libary, because that’s what we built, an ordinary shared library.

The one very important caveat is that you should not pass pointers to Go allocated memory back to the C++ side; that’s why we use an output parameter (v_out). Even if you maintain a reference to it on the Go side so that the garbage collector doesn’t reclaim it, the Go runtime reserves the right to move that memory if they build a copying garbage collector. Lots of details in issue #8310.

Passing C++ allocated memory to Go is fine. Go will not garbage collect memory it did not allocate. There rules here are the same as for cgo.

July 15, 2015

Building shared libraries in Go: Part 1

Posted in Software at 03:22 by graham

Since 1.5, we can write C-style shared libraries (.so) in Go. These can be used directly from C and C++, but also from any language that can use a C shared library, which is most languages. Here’s the original design document. Let’s do a very simple example and call it from Python. In Part 2 we’ll do a more complex example and call it from C++.

Calling Go from Python

package main

import "C"

//export DoubleIt
func DoubleIt(x int) int {
        return x * 2
}

func main() {}

Save that in your GOPATH as doubler/main.go. The exported symbols (the functions the shared library provides) must be in a main package, with a required but ignored main function. They must be marked with magic comment //export <name> (no space), because go build will call cgo.

go build -o libdoubler.so -buildmode=c-shared doubler

This puts libdoubler.so in your current directory. Let’s check we really have a dynamic shared library:

$ file libdoubler.so 
libdoubler.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked ...

$ nm -D libdoubler.so | grep "T DoubleIt"
000000000005d230 T DoubleIt

Well that looks good. Let’s call it from Python, because Python’s ctypes makes this incredibly easy:

>>> import ctypes
>>> lib = ctypes.CDLL("libdoubler.so")
>>> lib.DoubleIt(21)
42

Ta da!

For me this ability to build normal shared libraries makes Go a first-class language on Unix. In later posts we’ll do a more complex example with C++, and time permitting a SWIG example with Ruby.

July 10, 2015

How memory is allocated

Posted in Software at 16:38 by graham

tl;dr man 2 brk

Last year when I was learning assembler, I was asking myself how to allocate memory without malloc. Usually memory is either allocated for us by our language, or we do it with new or malloc. But malloc is a library function, it’s not a system call. How does malloc itself get memory from the kernel? To answer that we need to look at the layout of a program in memory.

On Linux amd64, every process gets it’s own 128 Tb virtual address space. The program code, global data, debugging information and so on are loaded at the bottom of that space, working ‘upwards’ (bigger numeric addresses). Then comes the heap, where we are going to allocate some memory. Where the heap ends is called the program break. Then there is a very large gap, which the heap will grow into. At the top of the address space (0x7fffffffffff) is the stack, which will grow downwards, back towards the top of the heap. Here is a graphic of virtual memory layout

To allocate memory on the heap, we simply ask the kernel to move the program break up. The space between old program break and new program break is our memory. The system call is brk. First we have to find out where it is now. brk returns the current position, so we simply have to call it. We pass it 0, which is an invalid value, so that it doesn’t change anything.

    mov $12, %rax   # brk syscall number
    mov $0, %rdi    # 0 is invalid, want to get current position
    syscall

When that returns, the current position is in rax. Let’s allocate 4 bytes, by asking the kernel to move our break up by four bytes:

    mov %rax, %rsi  # save current break

    mov %rax, %rdi  # move top of heap to here ...
    add $4, %rdi    # .. plus 4 bytes we allocate
    mov $12, %rax   # brk, again
    syscall

We can now store anything we want at the address pointed at by rsi, where we saved the start of our allocated space. Here is a full assembly program which puts “HI\n” into that space, and prints it out. alloc.s. Compile, link, run:

as -o alloc.o alloc.s
ld -o alloc alloc.o
./alloc

To free memory, you do the opposite, you move the break back down. That allows the kernel to re-use that space. Happy allocating!

June 30, 2015

Go: Slice search vs map lookup

Posted in Software at 07:09 by graham

tl;dr Use a map.

Computer science 101 tells us that maps are constant time access, O(1). But what is the constant? The map has to compute the hash, find the right bucket (array access), the right item within the bucket (another array access), and potentially do that multiple times as we walk a chain of buckets (if we overflowed the original bucket). At what point is it faster to iterate through an array comparing each item until we find the one we want?

Motivated by this comparison in C++ I decided to compare Go’s built-in map and slice types. The code is in a gist, a simple set of benchmark tests.

I tried two cases:

  • first a traditional key-value setup comparing map[string]string with []*Item{string,string}. The break-even point here is just five items. Under that the slice is faster, above it is slower.
  • second a set of integers, comparing map[int]struct{} with []int. The break-even point is ten items.

These results are similar to the C++ results. They mean we won’t be doing clever hacks in the name of performance. I call that good news. Use the obvious data structure and it will also be the right choice for performance.

Read the rest of this entry »

June 19, 2015

Software engineering practices

Posted in Software at 03:08 by graham

A selection of software engineering practices, from notes I took at an XTC meetup many years ago. They have survived the test of time very well. Practices change much slower than tools, and are typically a better investment.

  • Keep your methods short.
  • System should always be running – this means you need either live upgrades or a cluster.
  • Always have a goal in mind – visible task. For example keep you current task on an index card stuck to the side of your monitor.
  • Code should express intent – self documenting code.
  • Verbose test names – Think of test methods names as a sentence.
  • The code is the design.
  • Do not duplicate code, effort, anything.
  • Twice is a smell, three times is a pattern.
  • No broken windows. Fight entropy.
  • Check everything into source control. Tools, libraries, documentation, everything.
  • Separate things that change.
  • Write pseudo code first and keep it as comments if it is still useful. OR, write pseudo code as methods and then flesh out.
  • Code for the common case – focus on building functionality that is the most useful first. 80% value for 20% effort.
  • Text is king.
  • Have courage – don’t talk instead of doing – resolve design debates by implementing the alternatives.
  • Take a break.
  • Proceed in small steps / small iterations.
  • Understand the domain. Better domain understanding lowers communication cost and means you can use vaguer specifications.
  • Make it work, then make it right, then make it fast.
  • Strive for a coherent abstraction – does each ‘unit’ fit together.
  • Open black boxes – look into bits of legacy systems you don’t know.
  • Automate.
  • Avoid ‘Manager’ objects – instead make them more specific: Retriever, Calculator, Finder, etc.
  • Think in terms of interfaces, of behaviour, not of data.
  • No magic: No wizards.

May 27, 2015

Go: The price of interface{}

Posted in Software at 00:43 by graham

Go’s empty interface{} is the interface that everything implements. It allows functions that can be passed any type. The function func f(any interface{}) can be called with a string f("a string"), an integer f(42), a custom type, or anything else.

This flexibility comes at a cost. When you assign a value to a type interface{}, Go will call runtime.convT2E to create the interface structure (read more about Go interface internals). That requires a memory allocation. More memory allocations means more garbage on the heap, which means longer garbage collection pauses.

Read the rest of this entry »

March 2, 2015

Quotes from veteran software engineers

Posted in Software at 07:53 by graham

The software industry is the most fashion-conscious industry I know of.
– Ivar Jacobson
If you take some of the programs that exist today, they are more complex that just about any artefact that humankind has build before.
– Bertand Meyer
The best path to high-quality software is talented experts who share a pretty clear sense of what they want to produce. I have no idea how to produce good software without talented programmers.
– Peter Weinberger

Masterminds of Programming is a fascinating book, where the authors get many of our industry’s most highly regarded veterans to speak out about basically anything software related. The hook is that they’re being interviewed about the programming language they created.

Here are some of the best quotes and most interesting historical anecdotes.

Read the rest of this entry »

January 31, 2015

Raw sockets in Go: Link layer

Posted in Software at 21:55 by graham

Continuing our dive into the Internet Protocol Suite from Go (See part 1 Raw sockets in Go: IP layer), we are going to the link layer, so we can see the IP headers. This will also allow us to craft our own IP headers, or handle address families outside IP. We’ll send ping packets (ICMP echo request) and watch the kernel’s response.

Receive

This isn’t wrapped in Go, so we need a syscall. Otherwise it’s very similar to the IP layer in part 1, and pretty similar to the C equivalent.

On the first line of main we request the AF_INET family, meaning IPv4. We could ask for a different address family (AF_* constants) – here’s a list of address families. Most of the protocols in that list are rare (AF_IPX, AF_APPLETALK, etc). We’re in a IP world today.

Other useful address families:

  • AF_INET6 for IPv6.
  • AF_UNIX for unix domain sockets. It is used in net.DialUnix and net.ListenUnix. The POSIX name for AF_UNIX is AF_LOCAL, but Go largely sticks to AF_UNIX. They are equivalent.
  • An odd / interesting one is AF_NETLINK, which is for talking to the kernel. Read about it man 7 netlink or at Linux Journal. Docker has a netlink package.

The second parameter, SOCK_RAW is what makes this a raw socket, where we receive IP packets. SOCK_STREAM would give us TCP, SOCK_DGRAM would give UDP.

The third parameter filters packets so we only receive ICMP. You need a protocol here. As man 7 raw says “Receiving of all IP protocols via IPPROTO_RAW is not possible using raw sockets”. We’ll do that in the next post in this series, at the physical / device driver layer.

Build and run it as root (only root or CAP_NET_RAW can open raw sockets). In a different window ping localhost. You should see something like this:

45 00 00 3C EA FF 40 00 40 06 51 BA 7F 00 00 01 7F 00 00 01 …

This is the IP Header. First byte 45 is 4 for the IP version (IPv4), and 5 for length of this header (5 32-bit words), and so on. This is just like the receive example in the previous post except that we also see the IP header.

Try replacing IPPROTO_ICMP in the Socket call with IPPROTO_TCP, and wget localhost. The first 20 bytes will be similar (the IP header), then you should see a TCP packet, and finally HTTP.

Read the rest of this entry »

« Previous entries Next Page » Next Page »