Created
May 9, 2011 16:34
-
-
Save errzey/962839 to your computer and use it in GitHub Desktop.
method mperf testing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdint.h> | |
#include <errno.h> | |
#include <time.h> | |
#include <inttypes.h> | |
enum evhttp_cmd_type { | |
EVHTTP_REQ_GET = 1 << 0, | |
EVHTTP_REQ_POST = 1 << 1, | |
EVHTTP_REQ_HEAD = 1 << 2, | |
EVHTTP_REQ_PUT = 1 << 3, | |
EVHTTP_REQ_DELETE = 1 << 4, | |
EVHTTP_REQ_OPTIONS = 1 << 5, | |
EVHTTP_REQ_TRACE = 1 << 6, | |
EVHTTP_REQ_CONNECT = 1 << 7, | |
EVHTTP_REQ_PATCH = 1 << 8 | |
}; | |
int | |
evhttp_parse_request_line(char * line) { | |
char * method; | |
char * uri; | |
char * ver; | |
int type; | |
/* Parse the request line */ | |
method = strsep(&line, " "); | |
if (line == NULL) { | |
return -1; | |
} | |
uri = strsep(&line, " "); | |
if (line == NULL) { | |
return -1; | |
} | |
ver = strsep(&line, " "); | |
if (line != NULL) { | |
return -1; | |
} | |
/* First line */ | |
if (strcmp(method, "GET") == 0) { | |
type = EVHTTP_REQ_GET; | |
} else if (strcmp(method, "POST") == 0) { | |
type = EVHTTP_REQ_POST; | |
} else if (strcmp(method, "HEAD") == 0) { | |
type = EVHTTP_REQ_HEAD; | |
} else if (strcmp(method, "PUT") == 0) { | |
type = EVHTTP_REQ_PUT; | |
} else if (strcmp(method, "DELETE") == 0) { | |
type = EVHTTP_REQ_DELETE; | |
} else if (strcmp(method, "OPTIONS") == 0) { | |
type = EVHTTP_REQ_OPTIONS; | |
} else if (strcmp(method, "TRACE") == 0) { | |
type = EVHTTP_REQ_TRACE; | |
} else if (strcmp(method, "PATCH") == 0) { | |
type = EVHTTP_REQ_PATCH; | |
} else { | |
type = -1; | |
} | |
return type; | |
} /* evhttp_parse_request_line */ | |
int | |
optimized_parse_request_line_v2(char * line) { | |
char * method; | |
char * uri; | |
char * ver; | |
size_t mlen; | |
uint32_t u32; | |
uint64_t u64; | |
int type = -1; | |
method = strsep(&line, " "); | |
if (!line) { | |
return -1; | |
} | |
uri = strsep(&line, " "); | |
if (!line) { | |
return -1; | |
} | |
ver = strsep(&line, " "); | |
if (line) { | |
return -1; | |
} | |
mlen = (uri - method) - 1; | |
switch (mlen) { | |
case 3: | |
u32 = *((uint32_t *)method); | |
/* GET\0 == 0x00544547 */ | |
/* PUT\0 == 0x00545550 */ | |
if (u32 == 0x00544547) { | |
type = EVHTTP_REQ_GET; | |
} else if (u32 == 0x00545550) { | |
type = EVHTTP_REQ_PUT; | |
} | |
break; | |
case 4: | |
u32 = *((uint32_t *)method); | |
/* POST == 0x54534F50 */ | |
/* HEAD == 0x44414548 */ | |
if (u32 == 0x54534F50) { | |
type = EVHTTP_REQ_POST; | |
} else if (u32 == 0x44414548) { | |
type = EVHTTP_REQ_HEAD; | |
} | |
break; | |
case 5: | |
/* PATCH\0 == 0x4843544150 */ | |
/* TRACE\0 == 0x4543415254 */ | |
u64 = *((uint64_t *)method); | |
if ((u64 & 0xFFFFFFFFFFFF) == 0x4843544150) { | |
type = EVHTTP_REQ_PATCH; | |
} else if ((u64 & 0xFFFFFFFFFFFF) == 0x4543415254) { | |
type = EVHTTP_REQ_TRACE; | |
} | |
break; | |
case 6: | |
/* DELETE\0 == 0x4554454C4544 */ | |
u64 = *((uint64_t *)method); | |
if ((u64 & 0xFFFFFFFFFFFFFF) == 0x4554454C4544) { | |
type = EVHTTP_REQ_DELETE; | |
} | |
break; | |
case 7: | |
/* OPTIONS\0 == 0x534E4F4954504F */ | |
/* CONNECT\0 == 0x5443454E4E4F43 */ | |
u64 = *((uint64_t *)method); | |
if ((u64 & 0xFFFFFFFFFFFFFFFF) == 0x534E4F4954504F) { | |
type = EVHTTP_REQ_OPTIONS; | |
} else if ((u64 & 0xFFFFFFFFFFFFFFFF) == 0x5443454E4E4F43) { | |
type = EVHTTP_REQ_CONNECT; | |
} | |
break; | |
} /* switch */ | |
return type; | |
} /* optimized_parse_request_line_v2 */ | |
int | |
optimized_parse_request_line_v1_2(char * line) { | |
char * method; | |
char * uri; | |
char * ver; | |
size_t mlen; | |
int type = -1; | |
method = strsep(&line, " "); | |
if (!line) { | |
return -1; | |
} | |
uri = strsep(&line, " "); | |
if (!line) { | |
return -1; | |
} | |
ver = strsep(&line, " "); | |
if (line) { | |
return -1; | |
} | |
mlen = (uri - method) - 1; | |
switch (mlen) { | |
case 3: | |
switch (*method) { | |
case 'G': | |
if (!strncmp(method, "GET", 3)) { | |
type = EVHTTP_REQ_GET; | |
} | |
break; | |
case 'P': | |
if (!strncmp(method, "PUT", 3)) { | |
type = EVHTTP_REQ_PUT; | |
} | |
break; | |
default: | |
break; | |
} | |
break; | |
case 4: | |
switch (*method) { | |
case 'P': | |
if (!strncmp(method, "POST", 4)) { | |
type = EVHTTP_REQ_POST; | |
} | |
break; | |
case 'H': | |
if (!strncmp(method, "HEAD", 4)) { | |
type = EVHTTP_REQ_HEAD; | |
} | |
break; | |
default: | |
break; | |
} | |
case 5: | |
switch (*method) { | |
case 'P': | |
if (!strncmp(method, "PATCH", 5)) { | |
type = EVHTTP_REQ_PATCH; | |
} | |
break; | |
case 'T': | |
if (!strncmp(method, "TRACE", 5)) { | |
type = EVHTTP_REQ_TRACE; | |
} | |
break; | |
default: | |
break; | |
} | |
break; | |
case 6: | |
if (!strncmp(method, "DELETE", 6)) { | |
type = EVHTTP_REQ_DELETE; | |
} | |
break; | |
case 7: | |
switch (*method) { | |
case 'O': | |
if (!strncmp(method, "OPTIONS", 7)) { | |
type = EVHTTP_REQ_OPTIONS; | |
} | |
break; | |
case 'C': | |
if (!strncmp(method, "CONNECT", 7)) { | |
type = EVHTTP_REQ_CONNECT; | |
} | |
break; | |
default: | |
break; | |
} | |
break; | |
} /* switch */ | |
return type; | |
} /* optimized_parse_request_line_v1_2 */ | |
int | |
optimized_parse_request_line_v1_1(char * line) { | |
char * method; | |
char * uri; | |
char * ver; | |
size_t mlen; | |
int type = -1; | |
method = strsep(&line, " "); | |
if (!line) { | |
return -1; | |
} | |
uri = strsep(&line, " "); | |
if (!line) { | |
return -1; | |
} | |
ver = strsep(&line, " "); | |
if (line) { | |
return -1; | |
} | |
mlen = (uri - method) - 1; | |
switch (mlen) { | |
case 3: | |
switch (*method) { | |
case 'G': | |
if (!memcmp(method, "GET", 3)) { | |
type = EVHTTP_REQ_GET; | |
} | |
break; | |
case 'P': | |
if (!memcmp(method, "PUT", 3)) { | |
type = EVHTTP_REQ_PUT; | |
} | |
break; | |
default: | |
break; | |
} | |
break; | |
case 4: | |
switch (*method) { | |
case 'P': | |
if (!memcmp(method, "POST", 4)) { | |
type = EVHTTP_REQ_POST; | |
} | |
break; | |
case 'H': | |
if (!memcmp(method, "HEAD", 4)) { | |
type = EVHTTP_REQ_HEAD; | |
} | |
break; | |
default: | |
break; | |
} | |
case 5: | |
switch (*method) { | |
case 'P': | |
if (!memcmp(method, "PATCH", 5)) { | |
type = EVHTTP_REQ_PATCH; | |
} | |
break; | |
case 'T': | |
if (!memcmp(method, "TRACE", 5)) { | |
type = EVHTTP_REQ_TRACE; | |
} | |
break; | |
default: | |
break; | |
} | |
break; | |
case 6: | |
if (!memcmp(method, "DELETE", 6)) { | |
type = EVHTTP_REQ_DELETE; | |
} | |
break; | |
case 7: | |
switch (*method) { | |
case 'O': | |
if (!memcmp(method, "OPTIONS", 7)) { | |
type = EVHTTP_REQ_OPTIONS; | |
} | |
break; | |
case 'C': | |
if (!memcmp(method, "CONNECT", 7)) { | |
type = EVHTTP_REQ_CONNECT; | |
} | |
break; | |
default: | |
break; | |
} | |
break; | |
} /* switch */ | |
return type; | |
} /* optimized_parse_request_line_v1_1 */ | |
/* Using lookup tables (switch/case), along with using the length of the method | |
* to get to the right table entry quicker. */ | |
int | |
optimized_parse_request_line_v1(char * line) { | |
char * method; | |
char * uri; | |
char * ver; | |
size_t mlen; | |
int type = -1; | |
method = strsep(&line, " "); | |
if (!line) { | |
return -1; | |
} | |
uri = strsep(&line, " "); | |
if (!line) { | |
return -1; | |
} | |
ver = strsep(&line, " "); | |
if (line) { | |
return -1; | |
} | |
mlen = (uri - method) - 1; | |
switch (mlen) { | |
case 3: | |
/* The length of the method string is 3, meaning it can only be one of two methods: GET or PUT */ | |
/* Since both GET and PUT share the same character 'T' at the end, | |
* if the string doesn't have 'T', we can immediately determine this | |
* is an invalid HTTP method */ | |
if (method[2] != 'T') { | |
break; | |
} | |
switch (*method) { | |
case 'G': | |
/* This first byte is 'G', so make sure the next byte is | |
* 'E', if it isn't then this isn't a valid method */ | |
if (method[1] == 'E') { | |
type = EVHTTP_REQ_GET; | |
} | |
break; | |
case 'P': | |
/* First byte is P, check second byte for 'U', if not, | |
* we know it's an invalid method */ | |
if (method[1] == 'U') { | |
type = EVHTTP_REQ_PUT; | |
} | |
break; | |
default: | |
break; | |
} | |
break; | |
case 4: | |
/* The method length is 4 bytes, leaving only the methods "POST" and | |
* "HEAD" */ | |
switch (*method) { | |
case 'P': | |
if (method[3] == 'T' && method[2] == 'S' && method[1] == 'O') { | |
type = EVHTTP_REQ_POST; | |
} | |
break; | |
case 'H': | |
if (method[3] == 'D' && method[2] == 'A' && method[1] == 'E') { | |
type = EVHTTP_REQ_HEAD; | |
} | |
break; | |
default: | |
break; | |
} | |
case 5: | |
/* Method length is 5 bytes, which can only encompass PATCH and | |
* TRACE */ | |
switch (*method) { | |
case 'P': | |
if (method[4] == 'H' && method[3] == 'C' && method[2] == 'T' && method[1] == 'A') { | |
type = EVHTTP_REQ_PATCH; | |
} | |
break; | |
case 'T': | |
if (method[4] == 'E' && method[3] == 'C' && method[2] == 'A' && method[1] == 'R') { | |
type = EVHTTP_REQ_TRACE; | |
} | |
break; | |
default: | |
break; | |
} | |
break; | |
case 6: | |
/* Method length is 6, only valid method 6 bytes in length is DELEte | |
*/ | |
/* If the first byte isn't 'D' then it's invalid */ | |
if (*method != 'D') { | |
break; | |
} | |
if (method[5] == 'E' && method[4] == 'T' && method[3] == 'E' && method[2] == 'L' && method[1] == 'E') { | |
type = EVHTTP_REQ_DELETE; | |
} | |
break; | |
case 7: | |
/* Method length is 7, only valid methods are "OPTIONS" and | |
* "CONNECT" */ | |
switch (*method) { | |
case 'O': | |
if (method[6] == 'S' && method[5] == 'N' && method[4] == 'O' && | |
method[3] == 'I' && method[2] == 'T' && method[1] == 'P') { | |
type = EVHTTP_REQ_OPTIONS; | |
} | |
break; | |
case 'C': | |
/* T C E N N O C */ | |
if (method[6] == 'T' && method[5] == 'C' && method[4] == 'E' && | |
method[3] == 'N' && method[2] == 'N' && method[1] == 'O') { | |
type = EVHTTP_REQ_CONNECT; | |
} | |
break; | |
default: | |
break; | |
} | |
break; | |
} /* switch */ | |
return type; | |
} /* optimized_parse_request_line_v1 */ | |
#define LOOPS 800000 | |
int | |
main(int argc, char ** argv) { | |
int i; | |
if (argc <= 1) { | |
printf("Usage %s \"request line\"\n", argv[0]); | |
exit(1); | |
} | |
for (i = 0; i < LOOPS; i++) { | |
char * line = strdup(argv[1]); | |
evhttp_parse_request_line(line); | |
free(line); | |
} | |
for (i = 0; i < LOOPS; i++) { | |
char * line = strdup(argv[1]); | |
optimized_parse_request_line_v1(line); | |
free(line); | |
} | |
for (i = 0; i < LOOPS; i++) { | |
char * line = strdup(argv[1]); | |
optimized_parse_request_line_v1_1(line); | |
free(line); | |
} | |
for (i = 0; i < LOOPS; i++) { | |
char * line = strdup(argv[1]); | |
optimized_parse_request_line_v1_2(line); | |
free(line); | |
} | |
for (i = 0; i < LOOPS; i++) { | |
char * line = strdup(argv[1]); | |
optimized_parse_request_line_v2(line); | |
free(line); | |
} | |
return 0; | |
} /* main */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment