From patchwork Thu Oct 22 12:01:37 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Khoronzhuk X-Patchwork-Id: 55437 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-wi0-f199.google.com (mail-wi0-f199.google.com [209.85.212.199]) by patches.linaro.org (Postfix) with ESMTPS id 6251722AA5 for ; Thu, 22 Oct 2015 12:04:54 +0000 (UTC) Received: by wicfg8 with SMTP id fg8sf19436157wic.0 for ; Thu, 22 Oct 2015 05:04:53 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:delivered-to:from:to:date :message-id:in-reply-to:references:subject:precedence:list-id :list-unsubscribe:list-archive:list-post:list-help:list-subscribe :mime-version:content-type:content-transfer-encoding:errors-to :sender:x-original-sender:x-original-authentication-results :mailing-list; bh=gjij3Wy9Glvd3mb4FoZTfyc256wJABLPDM1fQpYUza0=; b=QKc43zuPh6Nk6evVDXDQ9TKCQRSiZJ6r4guKQt1kDvMya8Wle4uGv1aIP79u8qDYGB iNv9ftB3v20UolA0GMYed8WGwUv4LkwgThlfKRESGi1u1XT9POnociaRfsjGQwm+Ai1X 0E7kSDroo+ctl1WT3r6TILx7YF2luGCfAWdveSpPXulwqiVVvsj8TbnV0BY84jLL0c0z Y4BcT6c6oWLGYST5vJNESbiJ4AetxcP9MfCjbSvOEMFAoB93I6Z79avX6+/FernoeWcx 52b49Qw2b5t8Lv+jzoFp0zDBGGTUYMJKu9/emVZqWFAU8eRlsqEPJDBCf2vOwD76Z6ex A0QA== X-Gm-Message-State: ALoCoQk4IpO9WN7kXnyEKFmmNagaA+e4/gVOqHTgRfzXTKoO+/huxztkxgswFlManWRjMnICIZif X-Received: by 10.180.87.164 with SMTP id az4mr8275776wib.1.1445515493717; Thu, 22 Oct 2015 05:04:53 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.25.24.170 with SMTP id 42ls344768lfy.3.gmail; Thu, 22 Oct 2015 05:04:53 -0700 (PDT) X-Received: by 10.112.205.231 with SMTP id lj7mr8173118lbc.57.1445515493558; Thu, 22 Oct 2015 05:04:53 -0700 (PDT) Received: from mail-lf0-f48.google.com (mail-lf0-f48.google.com. [209.85.215.48]) by mx.google.com with ESMTPS id v139si9403329lfd.60.2015.10.22.05.04.53 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Oct 2015 05:04:53 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.48 as permitted sender) client-ip=209.85.215.48; Received: by lffz202 with SMTP id z202so45158938lff.3 for ; Thu, 22 Oct 2015 05:04:53 -0700 (PDT) X-Received: by 10.112.202.35 with SMTP id kf3mr8355905lbc.19.1445515493256; Thu, 22 Oct 2015 05:04:53 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.59.35 with SMTP id w3csp560775lbq; Thu, 22 Oct 2015 05:04:51 -0700 (PDT) X-Received: by 10.55.207.3 with SMTP id e3mr17813113qkj.32.1445515491867; Thu, 22 Oct 2015 05:04:51 -0700 (PDT) Received: from lists.linaro.org (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTP id e37si12936825qgd.116.2015.10.22.05.04.51; Thu, 22 Oct 2015 05:04:51 -0700 (PDT) Received-SPF: pass (google.com: domain of lng-odp-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) client-ip=54.225.227.206; Received: by lists.linaro.org (Postfix, from userid 109) id 7453F62BEA; Thu, 22 Oct 2015 12:04:51 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on ip-10-142-244-252 X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, URIBL_BLOCKED autolearn=disabled version=3.4.0 Received: from [127.0.0.1] (localhost [127.0.0.1]) by lists.linaro.org (Postfix) with ESMTP id 1E63A62023; Thu, 22 Oct 2015 12:02:23 +0000 (UTC) X-Original-To: lng-odp@lists.linaro.org Delivered-To: lng-odp@lists.linaro.org Received: by lists.linaro.org (Postfix, from userid 109) id 43A1861FFF; Thu, 22 Oct 2015 12:02:16 +0000 (UTC) Received: from mail-lf0-f44.google.com (mail-lf0-f44.google.com [209.85.215.44]) by lists.linaro.org (Postfix) with ESMTPS id 6D5C461CD9 for ; Thu, 22 Oct 2015 12:01:51 +0000 (UTC) Received: by lffz202 with SMTP id z202so45064822lff.3 for ; Thu, 22 Oct 2015 05:01:50 -0700 (PDT) X-Received: by 10.25.208.141 with SMTP id h135mr5490627lfg.81.1445515310381; Thu, 22 Oct 2015 05:01:50 -0700 (PDT) Received: from khorivan.synapse.com ([212.90.60.8]) by smtp.gmail.com with ESMTPSA id bn5sm2296353lbc.16.2015.10.22.05.01.49 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 22 Oct 2015 05:01:49 -0700 (PDT) From: Ivan Khoronzhuk To: lng-odp@lists.linaro.org, petri.savolainen@nokia.com Date: Thu, 22 Oct 2015 15:01:37 +0300 Message-Id: <1445515299-18496-4-git-send-email-ivan.khoronzhuk@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1445515299-18496-1-git-send-email-ivan.khoronzhuk@linaro.org> References: <1445515299-18496-1-git-send-email-ivan.khoronzhuk@linaro.org> X-Topics: patch Subject: [lng-odp] [API-NEXT PATCH v5 3/5] api: time: unbind CPU cycles from time API X-BeenThere: lng-odp@lists.linaro.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , MIME-Version: 1.0 Errors-To: lng-odp-bounces@lists.linaro.org Sender: "lng-odp" X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: ivan.khoronzhuk@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.48 as permitted sender) smtp.mailfrom=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 Current time API supposes that frequency of counter is equal to CPU frequency. But that's not always true, for instance, in case if no access to CPU cycle counter, another hi-resolution timer can be used, and it`s rate can be different from CPU rate. There is no big difference in which cycles to measure time, the better hi-resolution timer the better measurements. So, unbind CPU cycle counter from time API by eliminating word "cycle" as it's believed to be used with CPU. Also add new opaque type for time odp_time_t, as it asks user to use API and abstracts time from units. New odp_time_t requires several additional API functions to be added: odp_time_t odp_time_sum(odp_time_t t1, odp_time_t t2); int odp_time_cmp(odp_time_t t1, odp_time_t t2); uint64_t odp_time_to_u64(odp_time_t hdl); Also added new definition that represents 0 ticks for time - ODP_TIME_NULL. It can be used instead of odp_time_from_ns(0) for comparison and initialization. This patch changes only used time API, it doesn't change used var names for simplicity. This time API can be implemented with local timer counter, so shouldn't be used between threads. Signed-off-by: Ivan Khoronzhuk --- example/generator/odp_generator.c | 12 +++---- include/odp/api/time.h | 68 ++++++++++++++++++++++++++++------- test/performance/odp_pktio_perf.c | 49 +++++++++++++------------ test/validation/pktio/pktio.c | 20 +++++------ test/validation/scheduler/scheduler.c | 5 +-- test/validation/time/time.c | 27 +++++++------- 6 files changed, 114 insertions(+), 67 deletions(-) diff --git a/example/generator/odp_generator.c b/example/generator/odp_generator.c index be9597b..f84adc4 100644 --- a/example/generator/odp_generator.c +++ b/example/generator/odp_generator.c @@ -585,7 +585,7 @@ static void *gen_recv_thread(void *arg) */ static void print_global_stats(int num_workers) { - uint64_t start, wait, diff; + odp_time_t start, wait, diff; uint64_t pkts, pkts_prev = 0, pps, maximum_pps = 0; int verbose_interval = 20; odp_thrmask_t thrd_mask; @@ -593,8 +593,8 @@ static void print_global_stats(int num_workers) while (odp_thrmask_worker(&thrd_mask) < num_workers) continue; - wait = odp_time_ns_to_cycles(verbose_interval * ODP_TIME_SEC); - start = odp_time_cycles(); + wait = odp_time_from_ns(verbose_interval * ODP_TIME_SEC); + start = odp_time(); while (odp_thrmask_worker(&thrd_mask) == num_workers) { if (args->appl.number != -1 && @@ -603,11 +603,11 @@ static void print_global_stats(int num_workers) break; } - diff = odp_time_diff_cycles(start, odp_time_cycles()); - if (diff < wait) + diff = odp_time_diff(start, odp_time()); + if (odp_time_cmp(diff, wait) > 0) continue; - start = odp_time_cycles(); + start = odp_time(); if (args->appl.mode == APPL_MODE_RCV) { pkts = odp_atomic_load_u64(&counters.udp); diff --git a/include/odp/api/time.h b/include/odp/api/time.h index b0072fc..7ed4734 100644 --- a/include/odp/api/time.h +++ b/include/odp/api/time.h @@ -28,14 +28,25 @@ extern "C" { #define ODP_TIME_MSEC 1000000ULL /**< Millisecond in nsec */ #define ODP_TIME_SEC 1000000000ULL /**< Second in nsec */ +/** + * @typedef odp_time_t + * ODP time stamp. Time stamp can be local, so shouldn't be shared between + * threads. + */ /** - * Current time in CPU cycles - * - * @return Current time in CPU cycles + * @def ODP_TIME_NULL + * Zero time stamp */ -uint64_t odp_time_cycles(void); +/** + * Current time stamp. + * + * It should be hi-resolution time. + * + * @return Time stamp. + */ +odp_time_t odp_time(void); /** * Time difference @@ -43,29 +54,60 @@ uint64_t odp_time_cycles(void); * @param t1 First time stamp * @param t2 Second time stamp * - * @return Difference of time stamps in CPU cycles + * @return Difference of time stamps */ -uint64_t odp_time_diff_cycles(uint64_t t1, uint64_t t2); +odp_time_t odp_time_diff(odp_time_t t1, odp_time_t t2); +/** + * Time sum + * + * @param t1 Time stamp + * @param t2 Time stamp + * + * @return Sum of time stamps + */ +odp_time_t odp_time_sum(odp_time_t t1, odp_time_t t2); /** - * Convert CPU cycles to nanoseconds + * Convert time to nanoseconds * - * @param cycles Time in CPU cycles + * @param time Time * * @return Time in nanoseconds */ -uint64_t odp_time_cycles_to_ns(uint64_t cycles); - +uint64_t odp_time_to_ns(odp_time_t time); /** - * Convert nanoseconds to CPU cycles + * Convert nanoseconds to time * * @param ns Time in nanoseconds * - * @return Time in CPU cycles + * @return Time stamp + */ +odp_time_t odp_time_from_ns(uint64_t ns); + +/** + * Compare two times as absolute ranges + * + * @param t1 First time + * @param t2 Second time + * + * @retval -1 if t2 < t1, 0 if t1 = t2, 1 if t2 > t1 + */ +int odp_time_cmp(odp_time_t t1, odp_time_t t2); + +/** + * Get printable value for an odp_time_t + * + * @param time time to be printed + * @return uint64_t value that can be used to print/display this + * time + * + * @note This routine is intended to be used for diagnostic purposes + * to enable applications to generate a printable value that represents + * an odp_time_t time. */ -uint64_t odp_time_ns_to_cycles(uint64_t ns); +uint64_t odp_time_to_u64(odp_time_t time); /** * @} diff --git a/test/performance/odp_pktio_perf.c b/test/performance/odp_pktio_perf.c index ae5b4c0..cf29802 100644 --- a/test/performance/odp_pktio_perf.c +++ b/test/performance/odp_pktio_perf.c @@ -106,7 +106,7 @@ struct tx_stats_s { uint64_t tx_cnt; /* Packets transmitted */ uint64_t alloc_failures;/* Packet allocation failures */ uint64_t enq_failures; /* Enqueue failures */ - uint64_t idle_cycles; /* Idle cycle count in TX loop */ + odp_time_t idle_cycles; /* Idle cycle count in TX loop */ }; typedef union tx_stats_u { @@ -305,12 +305,12 @@ static void *run_thread_tx(void *arg) int thr_id; odp_queue_t outq; pkt_tx_stats_t *stats; - uint64_t burst_start_cycles, start_cycles, cur_cycles, send_duration; - uint64_t burst_gap_cycles; + odp_time_t start_cycles, cur_cycles, send_duration; + odp_time_t burst_start_cycles, burst_gap_cycles; uint32_t batch_len; int unsent_pkts = 0; odp_event_t tx_event[BATCH_LEN_MAX]; - uint64_t idle_start = 0; + odp_time_t idle_start = ODP_TIME_NULL; thread_args_t *targs = arg; @@ -328,30 +328,33 @@ static void *run_thread_tx(void *arg) if (outq == ODP_QUEUE_INVALID) LOG_ABORT("Failed to get output queue for thread %d\n", thr_id); - burst_gap_cycles = odp_time_ns_to_cycles( + burst_gap_cycles = odp_time_from_ns( ODP_TIME_SEC / (targs->pps / targs->batch_len)); - send_duration = odp_time_ns_to_cycles(targs->duration * ODP_TIME_SEC); + send_duration = odp_time_from_ns(targs->duration * ODP_TIME_SEC); odp_barrier_wait(&globals->tx_barrier); - cur_cycles = odp_time_cycles(); + cur_cycles = odp_time(); start_cycles = cur_cycles; - burst_start_cycles = odp_time_diff_cycles(burst_gap_cycles, cur_cycles); - while (odp_time_diff_cycles(start_cycles, cur_cycles) < send_duration) { + burst_start_cycles = odp_time_diff(burst_gap_cycles, cur_cycles); + while (odp_time_diff(start_cycles, cur_cycles) < send_duration) { unsigned alloc_cnt = 0, tx_cnt; - if (odp_time_diff_cycles(burst_start_cycles, cur_cycles) + if (odp_time_diff(burst_start_cycles, cur_cycles) < burst_gap_cycles) { - cur_cycles = odp_time_cycles(); - if (idle_start == 0) + cur_cycles = odp_time(); + if (!odp_time_cmp(ODP_TIME_NULL, idle_start)) idle_start = cur_cycles; continue; } - if (idle_start) { - stats->s.idle_cycles += odp_time_diff_cycles( - idle_start, cur_cycles); - idle_start = 0; + if (odp_time_cmp(ODP_TIME_NULL, idle_start)) { + odp_time_t diff = odp_time_diff(idle_start, cur_cycles); + + stats->s.idle_cycles = + odp_time_sum(diff, stats->s.idle_cycles); + + idle_start = ODP_TIME_NULL; } burst_start_cycles += burst_gap_cycles; @@ -365,14 +368,14 @@ static void *run_thread_tx(void *arg) stats->s.enq_failures += unsent_pkts; stats->s.tx_cnt += tx_cnt; - cur_cycles = odp_time_cycles(); + cur_cycles = odp_time(); } VPRINT(" %02d: TxPkts %-8"PRIu64" EnqFail %-6"PRIu64 " AllocFail %-6"PRIu64" Idle %"PRIu64"ms\n", thr_id, stats->s.tx_cnt, stats->s.enq_failures, stats->s.alloc_failures, - odp_time_cycles_to_ns(stats->s.idle_cycles)/1000/1000); + odp_time_to_ns(stats->s.idle_cycles) / (uint64_t)ODP_TIME_MSEC); return NULL; } @@ -591,13 +594,13 @@ static int setup_txrx_masks(odp_cpumask_t *thd_mask_tx, */ static void busy_loop_ns(uint64_t wait_ns) { - uint64_t diff; - uint64_t start_time = odp_time_cycles(); - uint64_t wait = odp_time_ns_to_cycles(wait_ns); + odp_time_t diff; + odp_time_t start_time = odp_time(); + odp_time_t wait = odp_time_from_ns(wait_ns); do { - diff = odp_time_diff_cycles(start_time, odp_time_cycles()); - } while (diff < wait); + diff = odp_time_diff(start_time, odp_time()); + } while (odp_time_cmp(diff, wait) > 0); } /* diff --git a/test/validation/pktio/pktio.c b/test/validation/pktio/pktio.c index 26ff4cd..d12e6b2 100644 --- a/test/validation/pktio/pktio.c +++ b/test/validation/pktio/pktio.c @@ -332,18 +332,18 @@ static int destroy_inq(odp_pktio_t pktio) static odp_event_t queue_deq_wait_time(odp_queue_t queue, uint64_t ns) { - uint64_t start, now, diff; + odp_time_t start, now, diff; odp_event_t ev; - start = odp_time_cycles(); + start = odp_time(); do { ev = odp_queue_deq(queue); if (ev != ODP_EVENT_INVALID) return ev; - now = odp_time_cycles(); - diff = odp_time_diff_cycles(start, now); - } while (odp_time_cycles_to_ns(diff) < ns); + now = odp_time(); + diff = odp_time_diff(start, now); + } while (odp_time_to_ns(diff) < ns); return ODP_EVENT_INVALID; } @@ -351,12 +351,12 @@ static odp_event_t queue_deq_wait_time(odp_queue_t queue, uint64_t ns) static odp_packet_t wait_for_packet(odp_queue_t queue, uint32_t seq, uint64_t ns) { - uint64_t start, now, diff; + odp_time_t start, now, diff; odp_event_t ev; odp_packet_t pkt = ODP_PACKET_INVALID; uint64_t wait; - start = odp_time_cycles(); + start = odp_time(); wait = odp_schedule_wait_time(ns); do { @@ -377,9 +377,9 @@ static odp_packet_t wait_for_packet(odp_queue_t queue, odp_event_free(ev); } - now = odp_time_cycles(); - diff = odp_time_diff_cycles(start, now); - } while (odp_time_cycles_to_ns(diff) < ns); + now = odp_time(); + diff = odp_time_diff(start, now); + } while (odp_time_to_ns(diff) < ns); CU_FAIL("failed to receive transmitted packet"); diff --git a/test/validation/scheduler/scheduler.c b/test/validation/scheduler/scheduler.c index 0c96dc3..96e0781 100644 --- a/test/validation/scheduler/scheduler.c +++ b/test/validation/scheduler/scheduler.c @@ -465,10 +465,11 @@ static void *schedule_common_(void *arg) CU_ASSERT(from != ODP_QUEUE_INVALID); if (locked) { int cnt; - uint64_t cycles = 0; + odp_time_t cycles = ODP_TIME_NULL; /* Do some work here to keep the thread busy */ for (cnt = 0; cnt < 1000; cnt++) - cycles += odp_time_cycles(); + cycles = odp_time_sum(cycles, + odp_time()); odp_spinlock_unlock(&globals->atomic_lock); } diff --git a/test/validation/time/time.c b/test/validation/time/time.c index 4b81c2c..a81d7ff 100644 --- a/test/validation/time/time.c +++ b/test/validation/time/time.c @@ -16,43 +16,44 @@ void time_test_odp_cycles_diff(void) { /* volatile to stop optimization of busy loop */ volatile int count = 0; - uint64_t diff, cycles1, cycles2; + odp_time_t diff, cycles1, cycles2; - cycles1 = odp_time_cycles(); + cycles1 = odp_time(); while (count < BUSY_LOOP_CNT) { count++; }; - cycles2 = odp_time_cycles(); - CU_ASSERT(cycles2 > cycles1); + cycles2 = odp_time(); + CU_ASSERT((odp_time_cmp(cycles1, cycles2) > 0)); - diff = odp_time_diff_cycles(cycles1, cycles2); - CU_ASSERT(diff > 0); + diff = odp_time_diff(cycles1, cycles2); + CU_ASSERT(odp_time_cmp(ODP_TIME_NULL, diff) > 0); } /* check that a negative cycles difference gives a reasonable result */ void time_test_odp_cycles_negative_diff(void) { - uint64_t diff, cycles1, cycles2; + odp_time_t diff, cycles1, cycles2; cycles1 = 10; cycles2 = 5; - diff = odp_time_diff_cycles(cycles1, cycles2); - CU_ASSERT(diff > 0); + diff = odp_time_diff(cycles1, cycles2); + CU_ASSERT(odp_time_cmp(ODP_TIME_NULL, diff) > 0); } /* check that related conversions come back to the same value */ void time_test_odp_time_conversion(void) { - uint64_t ns1, ns2, cycles; + uint64_t ns1, ns2; + odp_time_t cycles; uint64_t upper_limit, lower_limit; ns1 = 100; - cycles = odp_time_ns_to_cycles(ns1); - CU_ASSERT(cycles > 0); + cycles = odp_time_from_ns(ns1); + CU_ASSERT(odp_time_cmp(ODP_TIME_NULL, cycles) > 0); - ns2 = odp_time_cycles_to_ns(cycles); + ns2 = odp_time_to_ns(cycles); /* need to check within arithmetic tolerance that the same * value in ns is returned after conversions */