Subject: Re: [PATCH] Make strbuf_cmp inline, constify its arguments and optimize it a bit

From: Alex Riesen <[email-masked]>
Date: Mon, 8 Oct 2007 00:31:40 +0200

Wincent Colaiuta, Mon, Oct 08, 2007 00:12:17 +0200:
> El 7/10/2007, a las 23:54, Alex Riesen escribió:
> 
> >>... All the rest pretty much
> >>was worse than what we started from in that it needed to reevaluate
> >>more conditions and turned out more complicated and obfuscate even to
> >>the human reader.
> >
> >it _is_ smaller. And it is _measurably_ faster on that thing I have at
> >home (and old p4).
> 
> Can we see the numbers and the steps used to obtain them? I'm also a  
> little bit confused about how an inlined function can lead to a  
> smaller executable... or did you just mean lines-of-code?

I did mean the bytes of object code. I never said it produces a
smaller executable.

I compiled with gcc -O2 and -O4, gcc 4.1.2 (Ubuntu 4.1.2-0ubuntu4).
Cut the functions out into their own files and compile them to get the
object code. Compile with -S (assembly) to examine the generated code.
Compare.

#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>

struct strbuf {
	size_t alloc;
	size_t len;
	char *buf;
};

int strbuf_cmp2(struct strbuf *a, struct strbuf *b)
{
	int len = a->len < b->len ? a->len: b->len;
	int cmp = memcmp(a->buf, b->buf, len);
	if (cmp)
		return cmp;
	return a->len < b->len ? -1: a->len != b->len;
}

int strbuf_cmp1(struct strbuf *a, struct strbuf *b)
{
	int cmp;
	if (a->len < b->len) {
		cmp = memcmp(a->buf, b->buf, a->len);
		return cmp ? cmp : -1;
	} else {
		cmp = memcmp(a->buf, b->buf, b->len);
		return cmp ? cmp : a->len != b->len;
	}
}

int main(int argc, char *argv[], char *envp[])
{
	struct strbuf s1 = {
		.alloc = 0,
		.len = 50,
		.buf = "01234567890123456789012345678901234567890123456789",
	};
	struct strbuf s2 = {
		.alloc = 0,
		.len = 50,
		.buf = "0123456789012345678901234567890123456789",
	};
	struct strbuf s3 = {
		.alloc = 0,
		.len = 50,
		.buf = "0123456789012345678901234567890123456789012345678x",
	};
	struct timeval tv1, tv2, diff;
	unsigned n;
	int result;
#define CYCLES 0xffffffffu

	strbuf_cmp1(&s1, &s2);
	strbuf_cmp1(&s2, &s3);
	result = 0;
	gettimeofday(&tv1, NULL);
	for (n = CYCLES; n--; ) {
		result += strbuf_cmp1(&s1, &s2);
		result += strbuf_cmp1(&s2, &s3);
		result += strbuf_cmp1(&s1, &s3);
		result += strbuf_cmp1(&s1, &s1);
		result += n;
	}
	gettimeofday(&tv2, NULL);
	timersub(&tv2, &tv1, &diff);
	printf("ph=%ld.%ld (%d)\n", diff.tv_sec, diff.tv_usec, result);

	strbuf_cmp2(&s1, &s2);
	strbuf_cmp2(&s2, &s3);
	result = 0;
	gettimeofday(&tv1, NULL);
	for (n = CYCLES; n--; ) {
		result += strbuf_cmp2(&s1, &s2);
		result += strbuf_cmp2(&s2, &s3);
		result += strbuf_cmp2(&s1, &s3);
		result += strbuf_cmp2(&s1, &s1);
		result += n;
	}
	gettimeofday(&tv2, NULL);
	timersub(&tv2, &tv1, &diff);
	printf("ar=%ld.%ld (%d)\n", diff.tv_sec, diff.tv_usec, result);
	return 0;
}