/**
 *******************************************************************************
 * \brief
 ******************************************************************************/
void kv_async_init_ctxt_io(uint32_t num_ctxt,
                           uint32_t jobs,
                           uint32_t klen,
                           uint32_t vlen,
                           uint32_t LEN,
                           uint32_t secs)
{
    uint32_t job  = 0;
    uint32_t ctxt = 0;
    kv_t    *db[jobs];

    printf("ASYNC %dx%dx%d", klen, vlen, LEN); fflush(stdout);
    for (job=0; job<jobs; job++)
    {
        db[job] = (kv_t*)kv_db_create_fixed(LEN, klen+job, vlen);
    }
    printf("."); fflush(stdout);
    for (ctxt=0; ctxt<num_ctxt; ctxt++)
    {
        kv_async_init_ctxt(ctxt, secs);

        for (job=0; job<jobs; job++)
        {
            kv_async_set_job(KV_ASYNC_CB_SGD           |
                             KV_ASYNC_CB_MULTI_CTXT_IO |
                             KV_ASYNC_CB_GTEST,
                             ctxt, job, db[job], vlen, LEN);
            KV_TRC(pFT, "CREATE_JOB FIXED %dx%dx%d", klen+job, vlen, LEN);
        }
    }
    printf("> "); fflush(stdout);
}
/**
 *******************************************************************************
 * \brief
 ******************************************************************************/
TEST(FVT_KV_GOOD_PATH, SYNC_ASYNC_EASY)
{
    uint32_t klen   = 256;
    uint32_t vlen   = KV_64K;
    uint32_t LEN    = 20;
    uint32_t secs   = 5;

    kv_async_init_ctxt(ASYNC_SINGLE_CONTEXT, secs);
    kv_async_init_job_easy(ASYNC_SINGLE_CONTEXT);

    printf("start async jobs\n");
    kv_async_start_jobs();

    printf("start sync job\n");
    fvt_kv_utils_SGD_LOOP(kv_async_get_ark(ASYNC_SINGLE_CONTEXT),
                          kv_db_create_fixed, klen, vlen, LEN, secs);

    printf("wait for async jobs\n");
    kv_async_wait_jobs();
}
/**
 *******************************************************************************
 * \brief
 ******************************************************************************/
void kv_async_job_perf(uint32_t jobs, uint32_t klen, uint32_t vlen,uint32_t len)
{
    long int wr_us    = 0;
    long int rd_us    = 0;
    long int mil      = 1000000;
    float    wr_s     = 0;
    float    rd_s     = 0;
    float    wr_mb    = 0;
    float    rd_mb    = 0;
    uint64_t mb64_1   = (uint64_t)KV_1M;
    uint64_t wr_bytes = 0;
    uint64_t rd_bytes = 0;
    uint64_t ops      = 0;
    uint64_t post_ops = 0;
    uint64_t ios      = 0;
    uint64_t post_ios = 0;
    float    wr_ops   = 0;
    float    wr_ios   = 0;
    float    rd_ops   = 0;
    float    rd_ios   = 0;
    uint32_t secs     = 5;
    uint32_t job      = 0;
    struct timeval stop, start;

    kv_async_init_ctxt(0, secs);

    for (job=0; job<jobs; job++)
    {
        kv_async_init_job(KV_ASYNC_CB_SGD|KV_ASYNC_CB_WRITE_PERF,
                          ASYNC_SINGLE_CONTEXT,
                          job, klen+job, vlen, len);
    }
    pCTs->flags |= KV_ASYNC_CT_PERF;

    /* do writes */
    (void)ark_stats(kv_async_get_ark(ASYNC_SINGLE_CONTEXT), &ops, &ios);
    KV_TRC(pFT, "PERF wr: ops:%"PRIu64" ios:%"PRIu64"", ops, ios);
    gettimeofday(&start, NULL);
    kv_async_run_jobs();        /* run write jobs */
    KV_TRC(pFT, "writes done");
    gettimeofday(&stop, NULL);
    wr_us += (stop.tv_sec*mil  + stop.tv_usec) -
             (start.tv_sec*mil + start.tv_usec);
    (void)ark_stats(kv_async_get_ark(ASYNC_SINGLE_CONTEXT),&post_ops,&post_ios);
    KV_TRC(pFT, "PERF wr: ops:%"PRIu64" ios:%"PRIu64"", post_ops, post_ios);
    wr_ops += post_ops - ops;
    wr_ios += post_ios - ios;

    /* calc bytes written */
    for (job=0; job<jobs; job++)
    {
        wr_bytes += (klen+vlen+job)*len*(pCTs->pCBs+job)->perf_loops;
    }

    /* do reads */
    for (job=0; job<jobs; job++)
    {
        if ((pCTs->pCBs+job)->perf_loops)
        {
            (pCTs->pCBs+job)->perf_loops = 0;
            (pCTs->pCBs+job)->flags = KV_ASYNC_CB_GET    |
                                      KV_ASYNC_CB_QUEUED |
                                      KV_ASYNC_CB_READ_PERF;
        }
    }
    pCTs->flags |= KV_ASYNC_CT_RUNNING;

    (void)ark_stats(kv_async_get_ark(0), &ops, &ios);
    KV_TRC(pFT, "PERF rd: ops:%"PRIu64" ios:%"PRIu64"", ops, ios);
    gettimeofday(&start, NULL);
    kv_async_run_jobs();        /* run read jobs */
    gettimeofday(&stop, NULL);
    KV_TRC(pFT, "reads done");
    rd_us += (stop.tv_sec*mil  + stop.tv_usec) -
             (start.tv_sec*mil + start.tv_usec);
    (void)ark_stats(kv_async_get_ark(0), &post_ops, &post_ios);
    KV_TRC(pFT, "PERF rd: ops:%"PRIu64" ios:%"PRIu64"", post_ops, post_ios);
    rd_ops += post_ops - ops;
    rd_ios += post_ios - ios;

    ASSERT_EQ(0, ark_delete(pCTs->ark));

    /* calc bytes read */
    for (job=0; job<jobs; job++)
    {
        rd_bytes += vlen*len*(pCTs->pCBs+job)->perf_loops;
        kv_db_destroy((pCTs->pCBs+job)->db, (pCTs->pCBs+job)->len);
        if ((pCTs->pCBs+job)->gvalue)
            free((pCTs->pCBs+job)->gvalue);
    }

    /* calc and print results */
    wr_s  = (float)((float)wr_us/(float)mil);
    wr_mb = (float)((double)wr_bytes / (double)mb64_1);
    rd_s  = (float)((float)rd_us/(float)mil);
    rd_mb = (float)((double)rd_bytes / (double)mb64_1);

    printf("ASYNC %dx%dx%d writes: %.3d jobs %2.3f mb in %.1f secs at ",
            klen, vlen, len, jobs, wr_mb, wr_s);
    printf("%2.3f mbps, %6.0f op/s, %.0f io/s\n",
            wr_mb/wr_s,
            wr_ops/wr_s,
            wr_ios/wr_s);
    printf("ASYNC %dx%dx%d reads:  %.3d jobs %2.3f mb in %.1f secs at ",
            klen, vlen, len, jobs, rd_mb, rd_s);
    printf("%2.3f mbps, %6.0f op/s, %.0f io/s\n",
            rd_mb/rd_s,
            rd_ops/rd_s,
            rd_ios/rd_s);
}