/*
 * Client : tee_pthread_big_matrix_mult.c
 * TA     : tee_pthread_big_matrix_mult_TA (6e1ded57-9b32-4325-bde7-edb9acad7071)
 */


/* TestCase     : tee_pthread_big_matrix_mult_simple
 * Name         : Big Matrix matrix multiplication benchmark test
 * Description  : Multiplication of two big matrixes with performance comparison
 * Precondition : SMP capable SK.
 * Scenario     : 1. TA calculates matrix matrix product by
 *                   non-multithreaded approach
 *                2. TA calculates matrix matrix product concurently
 *                3. Results are compared
 *                4. Time consumed by each case is printed
 *                5. Timestamps are compared
 * Pass Cond    : Passed if multithreaded timestamp is less.
 */

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <tee_client_api.h>

static void usage(const char *progname);

static const TEEC_UUID uuid_benchmark_matrix_mult =
    { 0x6e1ded57, 0x9b32, 0x4325, {0xbd,0xe7,0xed,0xb9,0xac,0xad,0x70,0x71} };

enum { BENCHMARK_MATRIX_MULT };

static TEEC_Result tee_test(TEEC_Context *context,
                            int cmd_id,
                            const TEEC_UUID *uuid,
                            const unsigned ncpus)
{
    TEEC_Result res;
    TEEC_Session session;
    uint32_t returnOrigin;
    TEEC_Operation op;
    op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
                                     TEEC_NONE,
                                     TEEC_NONE,
                                     TEEC_NONE);
    op.params[0].value.a = ncpus;

    TEECS_SetCryptoClk(context, ENABLE_CRYPTO_CLK);
    res = TEEC_OpenSession(context, &session,
                           uuid, 0, NULL,
                           NULL, &returnOrigin);
    if (res != TEEC_SUCCESS) {
        printf("TEEC_OpenSession returned %s from %s\n",
               get_error_name(res),
               get_return_origin(returnOrigin));
        goto out;
    }

    res = TEEC_InvokeCommand(&session, cmd_id, &op, &returnOrigin);
    if (res != TEEC_SUCCESS) {
        printf("TEEC_InvokeCommand returned %s from %s\n",
               get_error_name(res),
               get_return_origin(returnOrigin));
    }

    TEEC_CloseSession(&session);

out:
    TEECS_SetCryptoClk(context, DISABLE_CRYPTO_CLK);
    return res;
}

int main(int argc, char **argv)
{
    TEEC_Result res;
    TEEC_Context context;

    unsigned ncpus = 8;

    if (argc > 2) {
        usage(argv[0]);
        return 1;
    }

    if (argc > 1) {
        ncpus = strtol(argv[1], NULL, 10);
        if (errno == ERANGE) {
            printf("Incorrect 'cpu_nums' specified\n");
            return 1;
        }

    }

    res = TEEC_InitializeContext(NULL, &context);
    if (res != TEEC_SUCCESS) {
        printf("InitializeContext failed: %s\n", get_error_name(res));
        goto out;
    }

    res = tee_test(&context,
                   BENCHMARK_MATRIX_MULT,
                   &uuid_benchmark_matrix_mult,
                   ncpus);
    if (res != TEEC_SUCCESS) {
        printf("tee_test failed: %d\n", res);
    }

    TEEC_FinalizeContext(&context);

out:
    if (res != TEEC_SUCCESS) {
        printf("TEST FAILED\n");
        return 1;
    }

    printf("TEST PASSED\n");
    return 0;
}

static void usage(const char *progname)
{
    printf("Test call pattern is:\n"
           "%s\t - launch TCs with default values.\n"
           "%s [cpu_nums]\t - explicitly specify the number of CPUs available\n",
           progname, progname);
}
