Skip to content

Instantly share code, notes, and snippets.

@avshabanov
Created May 5, 2015 05:44
Show Gist options
  • Save avshabanov/078859e818ec32e6b552 to your computer and use it in GitHub Desktop.
Save avshabanov/078859e818ec32e6b552 to your computer and use it in GitHub Desktop.
InvokeInterface: Java vs C
// gcc invoke_interface.c -std=c99 -O2 -o /tmp/iin
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
/* Common */
struct ClassMeta {
void ** itbls;
int itblsCount;
int size;
};
struct Object {
struct ClassMeta * _class;
};
struct InterfaceVtbl {
int _interfaceId;
};
/* Modify interface definition */
#define MODIFY_INTERFACE_ID (1000234234)
struct ModifyVtbl {
int _interfaceId;
// methods
int (* apply)(void * self, int value);
};
/* AddOne */
struct AddOne {
struct ClassMeta * _class;
};
static int AddOne_apply(void * self, int value) {
return value + 1;
}
static struct ModifyVtbl g_AddOne_ModifyVtbl = {
MODIFY_INTERFACE_ID,
&AddOne_apply
};
static void* g_AddOne_itbls[] = {
&g_AddOne_ModifyVtbl
};
static struct ClassMeta g_AddOne_ClassMeta = {
.size = sizeof(struct AddOne),
.itbls = g_AddOne_itbls,
.itblsCount = 1
};
/* DecOne */
struct DecOne {
struct ClassMeta * _class;
};
static int DecOne_apply(void * self, int value) {
return value - 1;
}
static struct ModifyVtbl g_DecOne_ModifyVtbl = {
MODIFY_INTERFACE_ID,
&DecOne_apply
};
static void* g_DecOne_itbls[] = {
&g_DecOne_ModifyVtbl
};
static struct ClassMeta g_DecOne_ClassMeta = {
.size = sizeof(struct DecOne),
.itbls = g_DecOne_itbls,
.itblsCount = 1
};
/* MulTwo */
struct MulTwo {
struct ClassMeta * _class;
};
static int MulTwo_apply(void * self, int value) {
return value * 2;
}
static struct ModifyVtbl g_MulTwo_ModifyVtbl = {
MODIFY_INTERFACE_ID,
&MulTwo_apply
};
static void* g_MulTwo_itbls[] = {
&g_MulTwo_ModifyVtbl
};
static struct ClassMeta g_MulTwo_ClassMeta = {
.size = sizeof(struct MulTwo),
.itbls = g_MulTwo_itbls,
.itblsCount = 1
};
/* MulInc */
struct MulInc {
struct ClassMeta * _class;
int a;
int b;
};
static int MulInc_apply(void * self, int value) {
struct MulInc * $this = self;
return value * $this->a + $this->b;
}
static struct ModifyVtbl g_MulInc_ModifyVtbl = {
MODIFY_INTERFACE_ID,
&MulInc_apply
};
static void* g_MulInc_itbls[] = {
&g_MulInc_ModifyVtbl
};
static struct ClassMeta g_MulInc_ClassMeta = {
.size = sizeof(struct MulInc),
.itbls = g_MulInc_itbls,
.itblsCount = 1
};
/* Helpers */
static struct InterfaceVtbl *
jb2c_rt_find_interface_unopt(int interfaceId, void ** itbls, int count) {
int i;
for (i = 1; i < count; ++i) {
struct InterfaceVtbl * iv = itbls[i];
if (iv->_interfaceId == interfaceId) {
return iv;
}
}
fprintf(stderr, "Unable to find interface %d", interfaceId);
abort();
return NULL;
}
static inline struct InterfaceVtbl *
jb2c_rt_find_interface(struct Object * o, int interfaceId) {
void ** itbls = o->_class->itbls;
int count = o->_class->itblsCount;
struct InterfaceVtbl * iv = itbls[0]; // we should have at least one interface here due to compile check
// optimized version: if first element is a vtbl - return it at once
if (iv->_interfaceId == interfaceId) {
return iv;
}
return jb2c_rt_find_interface_unopt(interfaceId, itbls, count);
}
/* tests */
static void demo_add_one() {
struct AddOne addOne;
addOne._class = &g_AddOne_ClassMeta;
// helper
struct ModifyVtbl * $i1 = ((struct ModifyVtbl *) jb2c_rt_find_interface((struct Object *) &addOne, MODIFY_INTERFACE_ID));
int result = $i1->apply(&addOne, 1000);
fprintf(stdout, "result=%d\n\n", result);
}
static struct Object ** mod_create(int count) {
char * mem = malloc(sizeof(struct MulInc) * count);
char * p = mem;
struct Object ** arr = malloc(sizeof(struct Object *) * count);
for (int i = 0; i < count; ++i, p += sizeof(struct MulInc)) {
if (i < 3) {
struct MulInc * r = (struct MulInc *) p; // new MulInc(i + 1, i)
r->_class = &g_MulInc_ClassMeta;
r->a = i + 1; // ctor
r->b = i; // ctor
arr[i] = (struct Object *) r;
continue;
}
if (i % 2 == 1) {
struct DecOne * r = (struct DecOne *) p; // new DecOne()
r->_class = &g_DecOne_ClassMeta;
arr[i] = (struct Object *) r;
continue;
}
if (i % 7 == 1) {
struct MulTwo * r = (struct MulTwo *) p; // new MulTwo()
r->_class = &g_MulTwo_ClassMeta;
arr[i] = (struct Object *) r;
continue;
}
{
struct AddOne * r = (struct AddOne *) p; // new AddOne()
r->_class = &g_AddOne_ClassMeta;
arr[i] = (struct Object *) r;
continue;
}
}
return arr;
}
int main(int argc, char ** argv) {
int count = 10;
int n;
int i;
int j;
struct timeval start;
struct timeval stop;
if (argc == 3) {
demo_add_one();
return 1;
}
if (argc > 1) {
count = atoi(argv[1]);
}
struct Object ** mods = mod_create(count);
fprintf(stdout, "created, count=%d\n", count);
for (j = 0; j < 10; ++j) {
n = 1;
gettimeofday(&start, NULL);
for (i = 0; i < count; ++i) {
struct Object * o = mods[i];
struct ModifyVtbl * $i1 = ((struct ModifyVtbl *) jb2c_rt_find_interface(o, MODIFY_INTERFACE_ID));
n = $i1->apply(o, n);
//fprintf(stdout, " [tmp] n=%d\n", n);
}
gettimeofday(&stop, NULL);
/* print the elapsed time */
long long diff = (stop.tv_usec - start.tv_usec) / 1000L;
fprintf(stdout, "Time=%lld ms, n = %d\n", diff, n);
}
return 0;
}
/**
* @author Alexander Shabanov
*/
public class InvokeInterfaceCost {
public interface Modify {
int apply(int value);
}
public static final class DecOne implements Modify {
@Override
public int apply(int value) {
return value - 1;
}
}
public static final class AddOne implements Modify {
@Override
public int apply(int value) {
return value + 1;
}
}
public static final class MulTwo implements Modify {
@Override
public int apply(int value) {
return value * 2;
}
}
public static final class MulInc implements Modify {
private final int a;
private final int b;
public MulInc(int a, int b) {
this.a = a;
this.b = b;
}
@Override
public int apply(int value) {
return value * a + b;
}
}
public static void main(String[] args) {
int count = 10;
if (args.length > 0) {
count = Integer.parseInt(args[0]);
}
System.out.println("count=" + count);
Modify[] m = create(count);
for (int i = 0; i < 10; ++i) {
System.out.println("Run #" + i);
final long start = System.currentTimeMillis();
int n = 1;
for (int j = 0; j < count; ++j) {
n = m[j].apply(n);
//System.out.println(" [tmp] n = " + n);
}
final long delta = System.currentTimeMillis() - start;
System.out.println(" Time=" + delta + "ms, n=" + n);
}
}
private static Modify[] create(int count) {
final Modify[] arr = new Modify[count];
for (int i = 0; i < count; ++i) {
if (i < 3) {
arr[i] = new MulInc(i + 1, i);
continue;
}
if (i % 2 == 1) {
arr[i] = new DecOne();
continue;
}
if (i % 7 == 1) {
arr[i] = new MulTwo();
continue;
}
arr[i] = new AddOne();
}
return arr;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment