Skip to content

Instantly share code, notes, and snippets.

@msg7086
Created February 13, 2025 04:02
Show Gist options
  • Save msg7086/f0cf87f73b4e4affa5e02a4f7c2973f4 to your computer and use it in GitHub Desktop.
Save msg7086/f0cf87f73b4e4affa5e02a4f7c2973f4 to your computer and use it in GitHub Desktop.
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <time.h>
#include "../common/lwindex_sscanf_unrolled.h"
#define ASSERT_EQ(a, b) \
if (a != b) { \
printf("Test failed: %s expected %d, got %d\n", #a, b, a); \
assert(a == b); \
return; \
}
static void test_main_index(void) {
// Test normal case
{
int stream_index = 0;
int64_t pos = 0, pts = 0, dts = 0;
int extradata_index = 0;
const char *input = "Index=1,POS=1000,PTS=2000,DTS=1900,EDI=5";
int result = sscanf_unrolled_main_index(input, &stream_index, &pos, &pts, &dts, &extradata_index);
ASSERT_EQ(result, 5);
ASSERT_EQ(stream_index, 1);
ASSERT_EQ(pos, 1000);
ASSERT_EQ(pts, 2000);
ASSERT_EQ(dts, 1900);
ASSERT_EQ(extradata_index, 5);
}
// Test invalid format
{
int stream_index = 0;
int64_t pos = 0, pts = 0, dts = 0;
int extradata_index = 0;
const char *input = "Invalid=1,POS=1000,PTS=2000,DTS=1900,EDI=5";
int result = sscanf_unrolled_main_index(input, &stream_index, &pos, &pts, &dts, &extradata_index);
ASSERT_EQ(result, 0);
}
// Test boundary values
{
int stream_index = 0;
int64_t pos = 0, pts = 0, dts = 0;
int extradata_index = 0;
const char *input = "Index=2147483647,POS=9223372036854775807,PTS=0,DTS=-9223372036854775808,EDI=-2147483648";
int result = sscanf_unrolled_main_index(input, &stream_index, &pos, &pts, &dts, &extradata_index);
ASSERT_EQ(result, 5);
ASSERT_EQ(stream_index, INT_MAX);
ASSERT_EQ(pos, LLONG_MAX);
ASSERT_EQ(pts, 0);
ASSERT_EQ(dts, LLONG_MIN);
ASSERT_EQ(extradata_index, INT_MIN);
}
}
static void test_video_index(void) {
// Test normal case
{
int key = 0, pict_type = 0, poc = 0, repeat_pict = 0, field_info = 0;
const char *input = "Key=1,Pic=2,POC=3,Repeat=1,Field=0";
int result = sscanf_unrolled_video_index(input, &key, &pict_type, &poc, &repeat_pict, &field_info);
ASSERT_EQ(result, 5);
ASSERT_EQ(key, 1);
ASSERT_EQ(pict_type, 2);
ASSERT_EQ(poc, 3);
ASSERT_EQ(repeat_pict, 1);
ASSERT_EQ(field_info, 0);
}
}
static void test_audio_index(void) {
// Test normal case
{
int frame_length = 0;
const char *input = "Length=1024";
int result = sscanf_unrolled_audio_index(input, &frame_length);
ASSERT_EQ(result, 1);
ASSERT_EQ(frame_length, 1024);
}
}
static void test_strto_functions(void) {
// Test my_strto_int
{
char *endptr;
ASSERT_EQ(my_strto_int("123", &endptr), 123);
ASSERT_EQ(my_strto_int("-123", &endptr), -123);
ASSERT_EQ(my_strto_int("-2147483648", &endptr), INT_MIN);
ASSERT_EQ(my_strto_int("2147483647", &endptr), INT_MAX);
}
// Test my_strto_int64_t
{
char *endptr;
ASSERT_EQ(my_strto_int64_t("123", &endptr), 123);
ASSERT_EQ(my_strto_int64_t("-123", &endptr), -123);
ASSERT_EQ(my_strto_int64_t("-9223372036854775808", &endptr), LLONG_MIN);
ASSERT_EQ(my_strto_int64_t("9223372036854775807", &endptr), LLONG_MAX);
}
}
// Add original sscanf functions for comparison
static int sscanf_original_main_index(const char *input, int *stream_index, int64_t *pos,
int64_t *pts, int64_t *dts, int *extradata_index) {
return sscanf(input, "Index=%d,POS=%" SCNd64 ",PTS=%" SCNd64 ",DTS=%" SCNd64 ",EDI=%d",
stream_index, pos, pts, dts, extradata_index);
}
static int sscanf_original_video_index(const char *input, int *key, int *pict_type,
int *poc, int *repeat_pict, int *field_info) {
return sscanf(input, "Key=%d,Pic=%d,POC=%d,Repeat=%d,Field=%d",
key, pict_type, poc, repeat_pict, field_info);
}
static int sscanf_original_audio_index(const char *input, int *frame_length) {
return sscanf(input, "Length=%d", frame_length);
}
static volatile int data = 0;
// Benchmark function
static void benchmark_parsing(int randomness) {
const int ITERATIONS = 2000000ull;
clock_t start, end;
double cpu_time_used;
double ops_original, ops_unrolled;
// Test data
const char *main_input = randomness == 1 ? "Index=1,POS=100023456,PTS=200023456,DTS=23456,EDI=5" : "Index=1,POS=1000,PTS=2000,DTS=1900,EDI=2";
const char *video_input = randomness == 1 ? "Key=1,Pic=2,POC=3,Repeat=1,Field=0" : "Key=1,Pic=2,POC=3,Repeat=0,Field=0";
const char *audio_input = randomness == 1 ? "Length=1024" : "Length=1000";
// Variables for parsing
int stream_index, extradata_index;
int64_t pos, pts, dts;
int key, pict_type, poc, repeat_pict, field_info;
int frame_length;
printf("\nPerformance Benchmark (%d iterations):\n", ITERATIONS);
printf("----------------------------------------\n");
// Benchmark main index parsing - Original
start = clock();
for (int i = 0; i < ITERATIONS; i++) {
sscanf_original_main_index(main_input, &stream_index, &pos, &pts, &dts, &extradata_index);
data += extradata_index;
}
end = clock();
ops_original = ITERATIONS * CLOCKS_PER_SEC / ((double) (end - start));
printf("Original main_index: %.2f ops/sec\n", ops_original);
// Benchmark main index parsing - Unrolled
start = clock();
for (int i = 0; i < ITERATIONS; i++) {
sscanf_unrolled_main_index(main_input, &stream_index, &pos, &pts, &dts, &extradata_index);
data += extradata_index;
}
end = clock();
ops_unrolled = ITERATIONS * CLOCKS_PER_SEC / ((double) (end - start));
printf("Unrolled main_index: %.2f ops/sec (%.1fx faster)\n", ops_unrolled, ops_unrolled/ops_original);
// Benchmark video index parsing - Original
start = clock();
for (int i = 0; i < ITERATIONS; i++) {
sscanf_original_video_index(video_input, &key, &pict_type, &poc, &repeat_pict, &field_info);
data += repeat_pict;
}
end = clock();
ops_original = ITERATIONS * CLOCKS_PER_SEC / ((double) (end - start));
printf("Original video_index: %.2f ops/sec\n", ops_original);
// Benchmark video index parsing - Unrolled
start = clock();
for (int i = 0; i < ITERATIONS; i++) {
sscanf_unrolled_video_index(video_input, &key, &pict_type, &poc, &repeat_pict, &field_info);
data += repeat_pict;
}
end = clock();
ops_unrolled = ITERATIONS * CLOCKS_PER_SEC / ((double) (end - start));
printf("Unrolled video_index: %.2f ops/sec (%.1fx faster)\n", ops_unrolled, ops_unrolled/ops_original);
// Benchmark audio index parsing - Original
start = clock();
for (int i = 0; i < ITERATIONS; i++) {
sscanf_original_audio_index(audio_input, &frame_length);
data += frame_length;
}
end = clock();
ops_original = ITERATIONS * CLOCKS_PER_SEC / ((double) (end - start));
printf("Original audio_index: %.2f ops/sec\n", ops_original);
// Benchmark audio index parsing - Unrolled
start = clock();
for (int i = 0; i < ITERATIONS; i++) {
sscanf_unrolled_audio_index(audio_input, &frame_length);
data += frame_length;
}
end = clock();
ops_unrolled = ITERATIONS * CLOCKS_PER_SEC / ((double) (end - start));
printf("Unrolled audio_index: %.2f ops/sec (%.1fx faster)\n", ops_unrolled, ops_unrolled/ops_original);
printf("----------------------------------------\n");
}
int main(int argc, char **argv) {
#if defined(__SSE4_1__)
printf("SSE4_1 is defined\n");
#endif
#if defined(__ARM_NEON)
printf("ARM NEON is defined\n");
#endif
// Run normal tests first
test_main_index();
test_video_index();
test_audio_index();
test_strto_functions();
printf("All tests passed!\n");
// return 0;
// Run performance benchmark
benchmark_parsing(argc);
return 0;
}
// x86-64
// gcc -O3 -march=core-avx2 -o test_lwindex_sscanf tests/test_lwindex_sscanf_unrolled.c
// arm64
// gcc -O3 -march=armv8-a -o test_lwindex_sscanf tests/test_lwindex_sscanf_unrolled.c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment