< Previous post | Next post >

[2025-12-02][Daily]

Investigating why some tasks can have various execution times


void test_convolution_varying_exec_time()
{
    dahl_block* a = BLOCK(testing_arena, 2, 5, 5, {
        {
            { 1, 1, 1, 1, 1 },
            { 1, 1, 1, 1, 1 },
            { 1, 1, 1, 1, 1 },
            { 1, 1, 1, 1, 1 },
            { 1, 1, 1, 1, 1 },
        },
        {
            { 1, 1, 1, 1, 1 },
            { 1, 1, 1, 1, 1 },
            { 1, 1, 1, 1, 1 },
            { 1, 1, 1, 1, 1 },
            { 1, 1, 1, 1, 1 },
        }
    });

    dahl_block* b = BLOCK(testing_arena, 2, 3, 3, {
        {
            { 1, 0, 1 },
            { 0, 1, 0 },
            { 1, 0, 1 },
        },
        {
            { 1, 0, 1 },
            { 0, 1, 0 },
            { 1, 0, 1 },
        }
    }); 

    dahl_matrix* expect = MATRIX(testing_arena, 3, 3, {
        { 10, 10, 10 },
        { 10, 10, 10 },
        { 10, 10, 10 },
    });

    dahl_matrix* out = matrix_init(testing_arena, (dahl_shape2d){ .x = 3, .y = 3 });

    for (size_t i = 0; i < 100; i++)
    {
        task_convolution_2d(a, b, out);
        ASSERT_MATRIX_EQUALS(expect, out);
    }
}

Here we run convolution task a hundred times on the same buffers. We notice that the first task is pretty slow, this is probably because the data have just been loaded and is not in cache yet. Because other tasks perform well.


void test_convolution_varying_exec_time()
{
    for (size_t i = 0; i < 100; i++)
    {
        dahl_block* a = BLOCK(testing_arena, 2, 5, 5, {
            {
                { 1, 1, 1, 1, 1 },
                { 1, 1, 1, 1, 1 },
                { 1, 1, 1, 1, 1 },
                { 1, 1, 1, 1, 1 },
                { 1, 1, 1, 1, 1 },
            },
            {
                { 1, 1, 1, 1, 1 },
                { 1, 1, 1, 1, 1 },
                { 1, 1, 1, 1, 1 },
                { 1, 1, 1, 1, 1 },
                { 1, 1, 1, 1, 1 },
            }
        });

        dahl_block* b = BLOCK(testing_arena, 2, 3, 3, {
            {
                { 1, 0, 1 },
                { 0, 1, 0 },
                { 1, 0, 1 },
            },
            {
                { 1, 0, 1 },
                { 0, 1, 0 },
                { 1, 0, 1 },
            }
        }); 

        dahl_matrix* expect = MATRIX(testing_arena, 3, 3, {
            { 10, 10, 10 },
            { 10, 10, 10 },
            { 10, 10, 10 },
        });

        dahl_matrix* out = matrix_init(testing_arena, (dahl_shape2d){ .x = 3, .y = 3 });

        task_convolution_2d(a, b, out);
        ASSERT_MATRIX_EQUALS(expect, out);

        TASK_FILL(out, 0);
        task_convolution_2d(a, b, out);
    }
}

We even notice that the first fill task is slow. Maybe there's just a "warm-up" phase?


void test_convolution_varying_exec_time()
{
    size_t n_samples = 100;
    dahl_shape4d a_shape = { .x = 270, .y = 360, .z = 2, .t = n_samples };
    dahl_shape4d b_shape = { .x = a_shape.x - 2, .y = a_shape.y - 2, .z = a_shape.z, .t = n_samples };
    dahl_shape3d out_shape = { .x = a_shape.x - b_shape.x + 1, .y = a_shape.y - b_shape.y + 1, .z = n_samples };

    dahl_tensor* a = tensor_init_random(testing_arena, a_shape, 0, 1);
    dahl_tensor* b = tensor_init_random(testing_arena, b_shape, 0, 1);
    dahl_block* out = block_init(testing_arena, out_shape);

    tensor_partition_along_t(a, DAHL_READ);
    tensor_partition_along_t(b, DAHL_READ);
    block_partition_along_z(out, DAHL_MUT);

    for (size_t i = 0; i < n_samples; i++)
    {
        task_convolution_2d(GET_SUB_BLOCK(a, i), GET_SUB_BLOCK(b, i), GET_SUB_MATRIX_MUT(out, i));
    }

    tensor_unpartition(a);
    tensor_unpartition(b);
    block_unpartition(out);

    dahl_arena_reset(testing_arena);
}

Here we increased input size to match the big fashion dataset, we don't see the "warm up" task, and don't see any problem, tasks ranges from 8 to 15 ms.

< Previous post | Next post >