vlm / asn1c

The ASN.1 Compiler
http://lionet.info/asn1c/
BSD 2-Clause "Simplified" License
1.05k stars 559 forks source link

Encoding performance of DER and XER #300

Open djelenc opened 6 years ago

djelenc commented 6 years ago

This is not really a bug report, but more of a question regarding performance. (Honestly, I suspect a bug in my own code, but insofar have been unable to find it.)

I'm trying to evaluate a certain ASN.1 schema using asn1c. I've written a simple test that measures the time needed to encode a bunch of messages in memory, and I find it strange that XER encoding outperforms DER encoding by roughly a factor of 2. Is such a result expected?

Here's the code doing the measurement.

// byte consumer func
print2fp(const void *buffer, size_t size, void *app_key) {
    FILE *stream = (FILE *)app_key;
    if (fwrite(buffer, 1, size, stream) != size)
        return -1;
    return 0;
}

// utility for measuring time
long double duration(const struct timeval *start, const struct timeval *stop) {
    return (long double)(stop->tv_usec - start->tv_usec) / 1000000 + (long double)(stop->tv_sec - start->tv_sec);
}

Each code snippet gets the following variables

struct timeval start, stop;
long double total = 0.0;

char buff[200];
size_t errSize = sizeof(buff);
size_t encodedSize;
size_t iterations = 100000;
FILE *dev_null = fopen("/dev/null", "w");

DER encoding

for (uint64_t i = 0; i < iterations; i++) {
    asn_enc_rval_t ec;
    gettimeofday(&start, NULL);
    // could also invoke with der_encode(&asn_DEF_Message, message, NULL, NULL)
    // but the same does not work with xer_encode, so I'm using /dev/null
    ec = der_encode(&asn_DEF_Message, message, print2fp, dev_null);
    gettimeofday(&stop, NULL);

    assert(ec.encoded != -1);
    assert(asn_check_constraints(&asn_DEF_Message, message, buff, &errSize) == 0);
    encodedSize = ec.encoded;

    total += duration(&start, &stop);
}

XER encoding:

for (uint64_t i = 0; i < iterations; i++) {
    asn_enc_rval_t ec;
    gettimeofday(&start, NULL);
    // invoking xer_encode(&asn_DEF_Message, message, XER_F_BASIC, NULL, NULL) segfaults,
    // because the function for consuming bytes (set to `NULL`)  is being dereferenced,
    // so I use /dev/null, instead
    ec = xer_encode(&asn_DEF_Message, message, XER_F_BASIC, print2fp, dev_null);
    gettimeofday(&stop, NULL);

    assert(ec.encoded != -1);
    assert(asn_check_constraints(&asn_DEF_Message, message, buff, &errSize) == 0);
    encodedSize = ec.encoded;

    total += duration(&start, &stop);
}

Running these two functions on a series of messages I consistently get that encoding DER is about a factor of 2 slower than XER. I find this surprising, since in the analog decoding example, DER consistently outperforms XER.

DemiMarie commented 4 years ago

How fast is BER encoding? DER is usually used in cryptographic operations where performance is less important.