Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
OpenXG UE
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenXG
OpenXG UE
Commits
a10068ce
Commit
a10068ce
authored
Feb 24, 2022
by
Robert Schmidt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Delete unused files
parent
42f8739d
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
0 additions
and
2226 deletions
+0
-2226
targets/RT/USER/lte-hwlat.c
targets/RT/USER/lte-hwlat.c
+0
-944
targets/RT/USER/lte-hwlat2.c
targets/RT/USER/lte-hwlat2.c
+0
-1282
No files found.
targets/RT/USER/lte-hwlat.c
deleted
100755 → 0
View file @
42f8739d
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sched.h>
#include <linux/sched.h>
#include <signal.h>
#include <execinfo.h>
#include <getopt.h>
#include <syscall.h>
#include <sys/sysinfo.h>
#include "assertions.h"
#include "PHY/types.h"
#include "PHY/defs.h"
#include <sys/time.h>
#define GET_TIME_INIT(num) struct timeval _timers[num]
#define GET_TIME_VAL(num) gettimeofday(&_timers[num], NULL)
#define TIME_VAL_TO_MS(num) (((double)_timers[num].tv_sec*1000.0) + ((double)_timers[num].tv_usec/1000.0))
#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
#include "../../ARCH/COMMON/common_lib.h"
#include "PHY/extern.h"
#include "SCHED/extern.h"
#include "LAYER2/MAC/extern.h"
#include "LAYER2/MAC/proto.h"
#define SYRIQ_CHANNEL_TESTER 0
#define SYRIQ_CHANNEL_TESTER2 0
#define SYRIQ_CHANNEL_DATA1 1
volatile
int
oai_exit
=
0
;
openair0_config_t
openair0_cfg
[
MAX_CARDS
];
#if 0
#define NB_ANTENNAS_RX 4
#define DevAssert(cOND) _Assert_(cOND, _Assert_Exit_, "")
#define malloc16(x) memalign(16,x)
#ifdef 0
static inline void* malloc16_clear( size_t size )
{
#ifdef __AVX2__
void* ptr = memalign(32, size);
#else
void* ptr = memalign(16, size);
#endif
if(ptr)
memset( ptr, 0, size );
return ptr;
}
#endif
#endif
typedef
struct
latency_stat
{
uint64_t
counter
;
uint64_t
stat250
;
uint64_t
stat500
;
uint64_t
stat600
;
uint64_t
stat700
;
uint64_t
stat800
;
uint64_t
stat1300
;
uint64_t
stat1500
;
uint64_t
stat2000
;
uint64_t
stat2500
;
uint64_t
stat3000
;
uint64_t
stat880
;
uint64_t
stat960
;
uint64_t
stat1040
;
uint64_t
stat1120
;
uint64_t
stat1200
;
}
latency_stat_t
;
typedef
struct
timing_stats
{
char
*
name
;
double
min
;
double
max
;
double
total
;
unsigned
int
count
;
}
timing_stats_t
;
//static struct timespec get_timespec_diff(
// struct timespec *start,
// struct timespec *stop )
//{
// struct timespec result;
//
// if ( ( stop->tv_nsec - start->tv_nsec ) < 0 ) {
// result.tv_sec = stop->tv_sec - start->tv_sec - 1;
// result.tv_nsec = stop->tv_nsec - start->tv_nsec + 1000000000;
// }
// else {
// result.tv_sec = stop->tv_sec - start->tv_sec;
// result.tv_nsec = stop->tv_nsec - start->tv_nsec;
// }
//
// return result;
//}
//static void measure_time (
// openair0_device *rf_device,
// struct timespec *start,
// struct timespec *stop,
// timing_stats_t *stats,
// boolean_t START,
// uint8_t PRINT_INTERVAL )
//{
// if ( START ) {
// clock_gettime( CLOCK_MONOTONIC, start );
// }
// else {
// clock_gettime( CLOCK_MONOTONIC, stop );
//
// struct timespec diff;
// double current = 0;
//// boolean_t show_stats = false;
//
// diff = get_timespec_diff( start, stop );
// current = (double)diff.tv_sec * 1000000 + (double)diff.tv_nsec / 1000;
//
// if ( current > stats->max ) {
// stats->max = current;
//// show_stats = true;
// }
// if ( stats->min == 0 || current < stats->min ) {
// stats->min = current;
//// show_stats = true;
// }
// stats->total += current;
//
//// if ( show_stats ) {
//// rf_device.trx_get_stats_func( &rf_device );
//// }
//
//// if ( stats->count % PRINT_INTERVAL == 0 ) {
//// double avg = stats->total / ( stats->count + 1 );
//// printf( "[%s][%d] Current : %.2lf µs, Min : %.2lf µs, Max : %.2lf µs, Avg : %.2lf µs\n",
//// stats->count, stats->name, current, stats->min, stats->max, avg );
//// }
//
// stats->count++;
// }
//}
int32_t
**
rxdata
;
int32_t
**
txdata
;
int
setup_ue_buffers
(
PHY_VARS_UE
**
phy_vars_ue
,
openair0_config_t
*
openair0_cfg
);
static
inline
void
saif_meas
(
unsigned
int
frame_rx
,
unsigned
int
subframe_rx
)
{
static
latency_stat_t
__thread
latency_stat
;
static
struct
timespec
__thread
last
=
{
0
};
struct
timespec
now
;
clock_gettime
(
CLOCK_MONOTONIC_RAW
,
&
now
);
if
(
last
.
tv_sec
)
{
uint64_t
diffTime
=
((
uint64_t
)
now
.
tv_sec
*
1000
*
1000
*
1000
+
now
.
tv_nsec
)
-
((
uint64_t
)
last
.
tv_sec
*
1000
*
1000
*
1000
+
last
.
tv_nsec
);
diffTime
/=
1000
;
latency_stat
.
counter
++
;
if
(
diffTime
<=
800
)
{
if
(
diffTime
<
250
)
latency_stat
.
stat250
++
;
else
if
(
diffTime
<
500
)
latency_stat
.
stat500
++
;
else
if
(
diffTime
<
600
)
latency_stat
.
stat600
++
;
else
if
(
diffTime
<
700
)
latency_stat
.
stat700
++
;
else
latency_stat
.
stat800
++
;
}
else
if
(
diffTime
>
1200
)
{
if
(
diffTime
<
1500
)
latency_stat
.
stat1300
++
;
else
if
(
diffTime
<
2000
)
latency_stat
.
stat1500
++
;
else
if
(
diffTime
<
2500
)
latency_stat
.
stat2000
++
;
else
if
(
diffTime
<
3000
)
latency_stat
.
stat2500
++
;
else
latency_stat
.
stat3000
++
;
}
else
if
(
diffTime
<=
880
)
latency_stat
.
stat880
++
;
else
if
(
diffTime
<=
960
)
latency_stat
.
stat960
++
;
else
if
(
diffTime
<=
1040
)
latency_stat
.
stat1040
++
;
else
if
(
diffTime
<
1120
)
latency_stat
.
stat1120
++
;
else
latency_stat
.
stat1200
++
;
if
(
(
diffTime
>=
1500
)
||
(
!
(
frame_rx
%
1024
)
&&
subframe_rx
==
0
)
)
{
time_t
current
=
time
(
NULL
);
printf
(
"
\n
"
);
printf
(
"%.2f Period stats cnt=%7.7ld 0.. 250=%7.7ld 250.. 500=%7.7ld 500.. 600=%7.7ld 600.. 700=%7.7ld 700.. 800=%7.7ld - (frame_rx=%u) - %s"
,
now
.
tv_sec
+
(
double
)
now
.
tv_nsec
/
1e9
,
latency_stat
.
counter
,
latency_stat
.
stat250
,
latency_stat
.
stat500
,
latency_stat
.
stat600
,
latency_stat
.
stat700
,
latency_stat
.
stat800
,
frame_rx
,
ctime
(
&
current
));
printf
(
"%.2f Period stats cnt=%7.7ld 800.. 880=%7.7ld 880.. 960=%7.7ld 960..1040=%7.7ld 1040..1120=%7.7ld 1120..1200=%7.7ld - (frame_rx=%u) - %s"
,
now
.
tv_sec
+
(
double
)
now
.
tv_nsec
/
1e9
,
latency_stat
.
counter
,
latency_stat
.
stat880
,
latency_stat
.
stat960
,
latency_stat
.
stat1040
,
latency_stat
.
stat1120
,
latency_stat
.
stat1200
,
frame_rx
,
ctime
(
&
current
));
printf
(
"%.2f Period stats cnt=%7.7ld 1200..1300=%7.7ld 1300..1500=%7.7ld 1500..2000=%7.7ld 2000..2500=%7.7ld >3000=%7.7ld - (frame_rx=%u) - %s"
,
now
.
tv_sec
+
(
double
)
now
.
tv_nsec
/
1e9
,
latency_stat
.
counter
,
latency_stat
.
stat1300
,
latency_stat
.
stat1500
,
latency_stat
.
stat2000
,
latency_stat
.
stat2500
,
latency_stat
.
stat3000
,
frame_rx
,
ctime
(
&
current
));
fflush
(
stdout
);
}
}
last
=
now
;
}
/* End of Changed by SYRTEM */
void
exit_fun
(
const
char
*
s
)
{
if
(
s
!=
NULL
)
{
printf
(
"%s %s() Exiting OAI softmodem: %s
\n
"
,
__FILE__
,
__FUNCTION__
,
s
);
}
oai_exit
=
1
;
}
void
init_thread
(
int
sched_runtime
,
int
sched_deadline
,
int
sched_fifo
,
char
*
name
)
{
#ifdef DEADLINE_SCHEDULER
if
(
sched_runtime
!=
0
)
{
struct
sched_attr
attr
=
{
0
};
attr
.
size
=
sizeof
(
attr
);
// This creates a .5 ms fpga_recv_cnt reservation
attr
.
sched_policy
=
SCHED_DEADLINE
;
attr
.
sched_runtime
=
sched_runtime
;
attr
.
sched_deadline
=
sched_deadline
;
attr
.
sched_period
=
0
;
AssertFatal
(
sched_setattr
(
0
,
&
attr
,
0
)
==
0
,
"[SCHED] main eNB thread: sched_setattr failed %s
\n
"
,
perror
(
errno
));
LOG_I
(
HW
,
"[SCHED][eNB] eNB main deadline thread %lu started on CPU %d
\n
"
,
(
unsigned
long
)
gettid
(),
sched_getcpu
());
}
#else
#ifdef CPU_AFFINITY
if
(
get_nprocs
()
>
2
)
{
for
(
j
=
1
;
j
<
get_nprocs
();
j
++
)
CPU_SET
(
j
,
&
cpuset
);
}
AssertFatal
(
0
==
pthread_setaffinity_np
(
pthread_self
(),
sizeof
(
cpu_set_t
),
&
cpuset
)
==
0
,
""
);
#endif
struct
sched_param
sp
;
sp
.
sched_priority
=
sched_fifo
;
AssertFatal
(
pthread_setschedparam
(
pthread_self
(),
SCHED_FIFO
,
&
sp
)
==
0
,
"Can't set thread priority, Are you root?
\n
"
);
#endif
// Lock memory from swapping. This is a process wide call (not constraint to this thread).
mlockall
(
MCL_CURRENT
|
MCL_FUTURE
);
pthread_setname_np
(
pthread_self
(),
name
);
}
int
main
(
void
)
{
int
ret
;
uint64_t
i
;
openair0_device
rf_device
;
openair0_timestamp
timestamp
=
0
;
unsigned
int
sub_frame
=
0
;
unsigned
int
frame_rx
=
0
;
unsigned
int
nb_antennas_tx
=
1
;
unsigned
int
nb_antennas_rx
=
1
;
openair0_cfg
[
0
].
mmapped_dma
=
0
;
openair0_cfg
[
0
].
configFilename
=
NULL
;
openair0_cfg
[
0
].
duplex_mode
=
duplex_mode_FDD
;
uint32_t
**
sendbuff
=
NULL
;
uint32_t
**
recvbuff
=
NULL
;
uint32_t
expected_value
=
0
;
uint32_t
received_value
=
0
;
int
nsamp
=
0
;
// 1 ms
int
antenna_id
=
1
;
int
c
=
0
;
int
numIter
=
0
;
int
fpga_loop
=
0
;
#if SYRIQ_CHANNEL_DATA1
uint64_t
first_ts
=
0
;
uint8_t
is_first_ts
=
0
;
uint64_t
trx_read_cnt
=
0
;
uint32_t
j
=
0
;
uint32_t
err_cnt
=
0
;
#else
int
failure
=
0
;
#endif
#if 0 // 5MHz BW
unsigned int nb_sample_per_tti = 7680;
openair0_cfg[0].sample_rate = 7.68e6;
openair0_cfg[0].samples_per_frame = nb_sample_per_tti*10;
openair0_cfg[0].rx_bw = 2.5e6;
openair0_cfg[0].tx_bw = 2.5e6;
openair0_cfg[0].num_rb_dl = 25;
#endif
#if 0 // 10MHz BW
unsigned int nb_sample_per_tti = 15360;
openair0_cfg[0].sample_rate = 15.36e6;
openair0_cfg[0].samples_per_frame = nb_sample_per_tti*10;
openair0_cfg[0].rx_bw = 5.0e6;
openair0_cfg[0].tx_bw = 5.0e6;
openair0_cfg[0].num_rb_dl = 50;
#endif
#if 1 // 20MHz BW
unsigned
int
nb_sample_per_tti
=
30720
;
openair0_cfg
[
0
].
sample_rate
=
30.72e6
;
openair0_cfg
[
0
].
samples_per_frame
=
nb_sample_per_tti
*
10
;
openair0_cfg
[
0
].
rx_bw
=
10.0e6
;
openair0_cfg
[
0
].
tx_bw
=
10.0e6
;
openair0_cfg
[
0
].
num_rb_dl
=
100
;
#endif
const
char
*
openair_dir
=
getenv
(
"OPENAIR_DIR"
);
const
char
*
ini_file
=
"/usr/local/etc/syriq/ue.band7.tm1.PRB100.NR20.dat"
;
int
readBlockSize
;
void
*
rxp
[
nb_antennas_rx
];
void
*
txp
[
nb_antennas_tx
];
// int32_t rxdata[1][nb_sample_per_tti*10+2048];
#if 0
int32_t **rxdata;
#endif
// init_thread(100000, 500000, sched_get_priority_max(SCHED_FIFO),"main UE");
printf
(
"LTE HARDWARE Latency debug utility
\n
"
);
printf
(
"INIT data buffers
\n
"
);
#if 0
rxdata = (int32_t**)memalign(32, nb_antennas_rx*sizeof(int32_t*) );
rxdata[0] = (int32_t*)memalign(32,(nb_sample_per_tti*10+2048)*sizeof(int32_t));
#else
rxdata
=
(
int32_t
**
)
malloc16
(
nb_antennas_rx
*
sizeof
(
int32_t
*
)
);
txdata
=
(
int32_t
**
)
malloc16
(
nb_antennas_tx
*
sizeof
(
int32_t
*
)
);
rxdata
[
0
]
=
(
int32_t
*
)
malloc16_clear
(
307200
*
sizeof
(
int32_t
)
);
txdata
[
0
]
=
(
int32_t
*
)
malloc16_clear
(
307200
*
sizeof
(
int32_t
)
);
#endif
printf
(
"INIT done
\n
"
);
memset
(
&
rf_device
,
0
,
sizeof
(
openair0_device
));
rf_device
.
host_type
=
BBU_HOST
;
openair0_cfg
[
0
].
duplex_mode
=
duplex_mode_FDD
;
openair0_cfg
[
0
].
rx_num_channels
=
1
;
openair0_cfg
[
0
].
tx_num_channels
=
1
;
// configure channel 0
for
(
i
=
0
;
i
<
openair0_cfg
[
0
].
rx_num_channels
;
i
++
)
{
printf
(
"configure channel %d
\n
"
,
i
);
openair0_cfg
[
0
].
autocal
[
i
]
=
1
;
openair0_cfg
[
0
].
rx_freq
[
i
]
=
2680000000
;
openair0_cfg
[
0
].
tx_freq
[
i
]
=
2560000000
;
openair0_cfg
[
0
].
rx_gain
[
i
]
=
61
;
openair0_cfg
[
0
].
tx_gain
[
i
]
=
90
;
}
if
(
openair_dir
)
{
openair0_cfg
[
0
].
configFilename
=
malloc
(
strlen
(
openair_dir
)
+
strlen
(
ini_file
)
+
2
);
sprintf
(
openair0_cfg
[
0
].
configFilename
,
"%s/%s"
,
openair_dir
,
ini_file
);
}
// printf("openair0_cfg[0].configFilename:%s\n", openair0_cfg[0].configFilename);
ret
=
openair0_device_load
(
&
rf_device
,
&
openair0_cfg
[
0
]
);
if
(
ret
!=
0
){
exit_fun
(
"Error loading device library"
);
exit
(
-
1
);
}
/* Runtime test
* 30 720 000 samples (4 bytes) for 1 sec (30 720 for 1 ms)
*/
puts
(
"* Starting the device"
);
// TIMING
// struct timespec start, stop; // tx_start, tx_stop;
// timing_stats_t rx_stats, tx_stats;
// rx_stats.name = strdup( "RX" );
// tx_stats.name = strdup( "TX" );
// TIMING
nsamp
=
307200
;
// 1 ms
sendbuff
=
memalign
(
128
,
nb_antennas_rx
*
sizeof
(
uint32_t
*
)
);
sendbuff
[
0
]
=
memalign
(
128
,
nsamp
*
sizeof
(
uint32_t
)
);
recvbuff
=
memalign
(
128
,
nb_antennas_rx
*
sizeof
(
uint32_t
*
)
);
recvbuff
[
0
]
=
memalign
(
128
,
nsamp
*
sizeof
(
uint32_t
)
);
// Create dummy buffer
for
(
c
=
0
;
c
<
nsamp
;
c
++
)
{
// sendbuff[0][c] = (c+1);
sendbuff
[
0
][
c
]
=
(
c
+
1
)
*
16
;
// sendbuff[0][c] = (nsamp-c);
recvbuff
[
0
][
c
]
=
0
;
}
GET_TIME_INIT
(
3
);
if
(
rf_device
.
trx_start_func
(
&
rf_device
)
<
0
)
{
printf
(
" device could not be started !
\n
"
);
return
-
1
;
}
// read 30720
// write 30720 ts+2*30720
// if tsread >= 2-307200 -> check expected value + status (RxoVer TxUnder)
rxp
[
0
]
=
(
void
*
)
&
rxdata
[
0
][
0
];
txp
[
0
]
=
(
void
*
)
&
txdata
[
0
][
0
];
timestamp
=
0
;
nsamp
=
30720
;
// 30720 => 1ms buffer
trx_read_cnt
=
100000
;
// 1 loop => 1ms (10sec=10000; 15min = 900000)
antenna_id
=
1
;
int
diff
=
0
;
int
compare_start
=
0
;
uint32_t
looploop
=
0
;
uint64_t
error_cnt
=
0
;
uint64_t
error_ts_start
;
for
(
i
=
0
;
i
<
trx_read_cnt
;
i
++
)
{
// printf("\n\n");
// ret = rf_device.trx_read_func( &rf_device, ×tamp, &(rxp[0][(i*30720)%307200]), nsamp, antenna_id );
// ret = rf_device.trx_read_func( &rf_device, ×tamp, recvbuff[0][(i*30720)%307200], nsamp, antenna_id );
rxp
[
0
]
=
(
void
*
)
&
rxdata
[
0
][(
i
*
30720
)
%
307200
];
GET_TIME_VAL
(
0
);
ret
=
rf_device
.
trx_read_func
(
&
rf_device
,
&
timestamp
,
rxp
,
nsamp
,
antenna_id
);
GET_TIME_VAL
(
1
);
if
(
ret
!=
nsamp
)
{
printf
(
"Error: nsamp received (%d) != nsamp required (%d)
\n
"
,
ret
,
nsamp
);
fflush
(
stdout
);
return
(
-
1
);
}
if
(
!
is_first_ts
)
{
first_ts
=
timestamp
;
is_first_ts
=
1
;
}
// printf("%d - trx_read_func ret=%d - ts = %d - @=0x%08lx\n", i, ret, timestamp, rxp[0] );
txp
[
0
]
=
(
void
*
)
&
(
txdata
[
0
][
((
i
*
30720
)
%
307200
+
2
*
30720
)
%
307200
]);
// printf(" i=%d @txp[0][0] = 0x%016lx\n", i, &(((uint32_t *)txp[0])[0]) );
// printf(" i=%d @txp[0][1] = 0x%016lx\n", i, &(((uint32_t *)txp[0])[1]) );
for
(
c
=
0
;
c
<
nsamp
;
c
++
)
{
(((
uint32_t
*
)
txp
[
0
])[
c
])
=
(
(((
timestamp
+
c
+
2
*
30720
)
<<
4
)
&
0x0000FFF0
)
+
(((
timestamp
+
c
+
2
*
30720
)
<<
8
)
&
0xFFF00000
)
);
}
// printf(" txp[0][%d] = 0x%x\n",0,((uint32_t *)(txp[0]))[0]);
// printf(" txp[0][%d] = 0x%x\n",1,((uint32_t *)(txp[0]))[1]);
// printf(" ...\n");
// printf(" txp[0][%d] = 0x%x\n",nsamp-2,((uint32_t *)(txp[0]))[nsamp-2]);
// printf(" txp[0][%d] = 0x%x\n",nsamp-1,((uint32_t *)(txp[0]))[nsamp-1]);
ret
=
rf_device
.
trx_write_func
(
&
rf_device
,
(
timestamp
+
2
*
30720
),
txp
,
nsamp
,
antenna_id
,
false
);
if
(
ret
!=
nsamp
)
{
printf
(
"Error: nsamp sent (%d) != nsamp required (%d)
\n
"
,
ret
,
nsamp
);
fflush
(
stdout
);
return
(
-
1
);
}
// printf("%d - trx_write_func ret=%d - ts = %d - @=0x%08lx\n", i, ret, (timestamp+2*30720), txp[0] );
if
(
timestamp
>=
(
first_ts
+
2
*
307200
))
{
// check Rx Overflow
// check Tx Underflow
// check Expected Value
for
(
c
=
0
;
c
<
nsamp
;
c
++
)
{
// LOOPBACK
#if 1
expected_value
=
((
timestamp
+
c
)
&
0xFFFFFF
);
received_value
=
((
uint32_t
*
)(
rxp
[
0
]))[
c
];
received_value
=
((
received_value
)
&
0xFFF
)
+
((
received_value
>>
4
)
&
0xFFF000
);
if
(
compare_start
==
0
)
{
compare_start
=
1
;
diff
=
expected_value
-
received_value
;
}
received_value
=
(
received_value
+
diff
)
&
0xFFFFFF
;
#if 1
if
(
expected_value
!=
received_value
)
{
if
(
!
error_cnt
)
error_ts_start
=
(
timestamp
+
c
);
else
{
if
(
looploop
<
32
)
printf
(
"%d - %d != %d - ts %d - raw 0x%x - diff %d
\n
"
,
looploop
,
expected_value
,
received_value
,
(
timestamp
+
c
),
((
uint32_t
*
)(
rxp
[
0
]))[
c
],
diff
);
looploop
++
;
}
error_cnt
++
;
if
(
!
(
error_cnt
%
102400
))
printf
(
" -> error detected : cnt=%d - start=%ld - stop=... diff=%d
\n
"
,
error_cnt
,
error_ts_start
,
diff
);
}
else
{
if
(
error_cnt
)
{
printf
(
" -> error detected : cnt=%d - start=%ld - stop=%ld
\n\n
"
,
error_cnt
,
error_ts_start
,
(
timestamp
+
c
)
);
looploop
=
0
;
}
error_cnt
=
0
;
}
#endif
#endif
// DEBUG mode 0
#if 0
received_value = ((uint32_t *)(rxp[0]))[c];
received_value = ((received_value)&0xFFF) + ((received_value>>4)&0xFFF000);
received_value = (received_value&0xFFFFFF);
if (compare_start == 0)
{
compare_start = 1;
expected_value = received_value;
}
else
{
expected_value++;
expected_value = (expected_value&0xFFFFFF);
}
if (expected_value != received_value)
{
if(!error_cnt)
error_ts_start = (timestamp + c);
error_cnt++;
}
else
{
if(error_cnt)
{
printf(" -> error detected : cnt=%d - start=%ld - stop=%ld\n\n",
error_cnt,
error_ts_start,
(timestamp + c) );
}
error_cnt=0;
}
// if (expected_value != received_value)
// {
// printf("%d -> %d != %d (ts+c=%ld)(raw=0x%08x)\n",
// looploop,
// expected_value, received_value,
// (timestamp + c),
// ((uint32_t *)(rxp[0]))[c] );
//
// if (received_value)
// expected_value = received_value;
// }
#endif
}
}
}
printf
(
"HwLat Application returns !!!
\n
"
);
fflush
(
stdout
);
sleep
(
1
);
printf
(
"
\n
"
);
rf_device
.
trx_end_func
(
&
rf_device
);
sleep
(
1
);
free
(
sendbuff
[
0
]);
free
(
sendbuff
);
free
(
recvbuff
[
0
]);
free
(
recvbuff
);
exit
(
0
);
return
(
0
);
// puts( "* Frequency modification test" );
// rf_device.trx_set_freq_func( &rf_device, &openair0_cfg[0], 0 );
// puts( "* Gain modification test" );
// rf_device.trx_set_gains_func( &rf_device, &openair0_cfg[0] ); // NOT working (cf. initialization)
//#if LTE_UE
// sleep(1);
GET_TIME_VAL
(
0
);
for
(
i
=
0
;
i
<
trx_read_cnt
;
i
++
)
{
printf
(
"
\n
"
);
ret
=
rf_device
.
trx_read_func
(
&
rf_device
,
&
timestamp
,
rxp
,
nsamp
,
antenna_id
);
printf
(
"* timestamp=%ld
\n
"
,
timestamp
);
#if 1
for
(
j
=
0
;
j
<
nsamp
;
j
++
)
{
if
(
((
uint32_t
*
)
rxp
[
0
])[
j
]
!=
((
expected_value
+
j
+
timestamp
)
%
307200
)
)
{
err_cnt
++
;
printf
(
"rxp[%06d]=0x%08x (expected 0x%08lx)
\n
"
,
j
,
((
uint32_t
*
)
rxp
[
0
])[
j
],
((
expected_value
+
j
+
timestamp
)
%
307200
)
);
}
if
(
err_cnt
>=
128
)
{
printf
(
"Error: more than 128 expected value failed !
\n
"
);
i
=
(
trx_read_cnt
-
1
);
j
=
nsamp
;
break
;
}
}
//expected_value = (expected_value + nsamp)%307200;
expected_value
=
(
expected_value
)
%
307200
;
#endif
}
GET_TIME_VAL
(
1
);
//#endif
/* ********** ********** */
/* SYRIQ_CHANNEL_DATA1 */
/* ********** ********** */
#if SYRIQ_CHANNEL_DATA1
// rf_device.trx_get_stats_func( &rf_device );
rf_device
.
trx_end_func
(
&
rf_device
);
printf
(
"
\n
* rf_device.trx_read_func(%d) x %d: %.6lf s
\n\n
"
,
nsamp
,
i
,
((
TIME_VAL_TO_MS
(
1
)
-
TIME_VAL_TO_MS
(
0
)))
/
1000
.
0
);
// rf_device.trx_get_stats_func( &rf_device );
#if 0
for (i = 0; i < nsamp; i++)
{
// if ( ((uint32_t *)rxp[0])[i] != i)
// {
err_cnt++;
printf("rxp[%06d]=0x%08x (expected 0x%08x)\n", i, ((uint32_t *)rxp[0])[i], i);
// }
// if (err_cnt > 256)
// {
// i = 307200;
// break;
// }
}
#endif
// for (i = 1024-32; i < 1024+32; i++)
// {
//// if ( ((uint32_t *)rxp[0])[i] != i)
//// {
// err_cnt++;
// printf("rxp[%06d]=0x%08x (expected 0x%08x)\n", i, ((uint32_t *)rxp[0])[i], i);
//// }
// if (err_cnt > 256)
// {
// i = 307200;
// break;
// }
// }
printf
(
"SYRIQ CHANNEL DATA1 done !!!
\n
"
);
sleep
(
1
);
return
(
0
);
#endif
/* ********** ********** */
/* SYRIQ_CHANNEL_DATA1 */
/* ********** ********** */
timestamp
=
0
;
ret
=
rf_device
.
trx_write_func
(
&
rf_device
,
timestamp
,
(
void
**
)
sendbuff
,
nsamp
,
antenna_id
,
false
);
printf
(
"* rf_device.trx_write_func returns %d
\n
"
,
ret
);
sleep
(
1
);
nsamp
=
30720
;
numIter
=
100000
;
for
(
c
=
0
;
c
<
numIter
;
c
++
)
{
fpga_loop
++
;
if
(
!
(
fpga_loop
%
1000
)
)
{
printf
(
"
\r
test loop %d / %d"
,
fpga_loop
,
numIter
);
fflush
(
stdout
);
}
// printf("* TEST : %08d\n", (c+1));
// measure_time( &rf_device, &start, &stop, &tx_stats, true, 10 );
// ret = rf_device.trx_write_func( &rf_device, timestamp, (void**)sendbuff, nsamp, antenna_id, false );
// printf("* rf_device.trx_write_func returns %d\n", ret);
// measure_time( &rf_device, &start, &stop, &tx_stats, false, 10 );
// sleep(1);
// measure_time( &rf_device, &start, &stop, &tx_stats, true, 10 );
ret
=
rf_device
.
trx_read_func
(
&
rf_device
,
&
timestamp
,
(
void
**
)
recvbuff
,
nsamp
,
antenna_id
);
// measure_time( &rf_device, &start, &stop, &tx_stats, false, 10 );
// Check the data
if
(
ret
>
0
)
{
/* ********** ********** */
/* SYRIQ_CHANNEL_TESTER */
/* ********** ********** */
#if SYRIQ_CHANNEL_TESTER
failure
=
0
;
for
(
i
=
0
;
i
<
ret
;
i
++
)
{
if
(
((
i
%
1024
)
==
0
)
||
((
i
%
1024
)
==
1
)
||
((
i
%
1024
)
==
2
)
||
((
i
%
1024
)
==
3
)
)
{
if
(
(
recvbuff
[
0
])[
i
]
!=
(
1020
+
((
i
%
1024
)
+
1
))
)
{
printf
(
"* ERROR (buff[0])[%d]: %d, expected %d
\n
"
,
i
,
(
uint32_t
)(
recvbuff
[
0
])[
i
],
((
i
%
1024
)
+
1
)
);
failure
=
1
;
}
}
else
if
(
(
recvbuff
[
0
])[
i
]
!=
((
i
%
1024
)
+
1
)
)
{
printf
(
"* ERROR (buff[0])[%d]: %d, expected %d
\n
"
,
i
,
(
uint32_t
)(
recvbuff
[
0
])[
i
],
((
i
%
1024
)
+
1
)
);
failure
=
1
;
}
else
{
printf
(
"* DONE (buff[0])[%d]: %d, expected %d
\n
"
,
i
,
(
uint32_t
)(
recvbuff
[
0
])[
i
],
((
i
%
1024
)
+
1
)
);
}
if
(
failure
)
break
;
}
if
(
failure
)
printf
(
"* ERROR recv %08d checked FAILURE ret=%d
\n
"
,
(
c
+
1
),
ret
);
else
{
// printf("* DONE recv %08d checked SUCCESSFULLY ret=%d\n", (c+1), ret);
}
#endif
/* ********** ********** */
/* SYRIQ_CHANNEL_TESTER2*/
/* ********** ********** */
#if SYRIQ_CHANNEL_TESTER2
// printf("* ret=%d timestamp=%ld (%ld)\n", ret, timestamp, (timestamp%307200));
failure
=
0
;
for
(
i
=
0
;
i
<
ret
;
i
++
)
{
// printf("* (recvbuff[0])[%d]: %d\n", i, (uint32_t)(recvbuff[0])[i]);
// printf("* timestamp+(i/1024+1)*1024 - 3 + i%1024: %d\n", (timestamp-nsamp+(i/1024+1)*1024 - 3 + i%1024)%307200 );
expected_value
=
((((
i
%
1024
)
+
1
)
/*>>4*/
)
&
0x00000FFF
);
if
(
((
i
%
1024
)
==
0
)
||
((
i
%
1024
)
==
1
)
||
((
i
%
1024
)
==
2
)
||
((
i
%
1024
)
==
3
)
)
{
expected_value
=
((((
timestamp
-
nsamp
+
(
i
/
1024
+
1
)
*
1024
-
3
+
i
%
1024
))
%
307200
));
if
(
(
recvbuff
[
0
])[
i
]
!=
expected_value
)
{
if
(
(
expected_value
==
0
)
&&
((
recvbuff
[
0
])[
i
]
!=
4915200
)
)
{
printf
(
"* ERROR (buff[0])[%d]: %d, expected %d
\n
"
,
i
,
(
uint32_t
)(
recvbuff
[
0
])[
i
],
expected_value
);
failure
=
1
;
}
if
(
(
expected_value
==
0
)
&&
((
recvbuff
[
0
])[
i
]
==
4915200
)
)
{
// printf("* DONE loop in circular buffer\n");
}
}
}
else
if
(
(
recvbuff
[
0
])[
i
]
!=
expected_value
)
{
printf
(
"* ERROR (buff[0])[%d]: %d, expected %d
\n
"
,
i
,
(
uint32_t
)(
recvbuff
[
0
])[
i
],
((
i
%
1024
)
+
1
)
);
failure
=
1
;
}
else
{
// printf("* DONE (buff[0])[%d]: %d, expected %d\n", i, (uint32_t)(recvbuff[0])[i], ((i%1024)+1) );
}
// if(failure)
// break;
}
if
(
failure
)
printf
(
"* ERROR recv %08d checked FAILURE ret=%d
\n
"
,
(
c
+
1
),
ret
);
else
{
// printf("* DONE recv %08d checked SUCCESSFULLY ret=%d\n", (c+1), ret);
}
#endif
#if LOOPBACK
#endif
}
else
{
printf
(
"* ERROR rf_device.trx_read_func returns %d
\n
"
,
ret
);
}
}
printf
(
"
\n
"
);
rf_device
.
trx_end_func
(
&
rf_device
);
sleep
(
1
);
free
(
sendbuff
[
0
]);
free
(
sendbuff
);
free
(
recvbuff
[
0
]);
free
(
recvbuff
);
exit
(
0
);
// END IS HERE !
rf_device
.
trx_set_freq_func
(
&
rf_device
,
&
openair0_cfg
[
0
],
0
);
if
(
rf_device
.
trx_start_func
(
&
rf_device
)
!=
0
)
{
printf
(
"Could not start the device
\n
"
);
oai_exit
=
1
;
}
while
(
!
oai_exit
){
rxp
[
0
]
=
(
void
*
)
&
rxdata
[
0
][
sub_frame
*
nb_sample_per_tti
];
readBlockSize
=
rf_device
.
trx_read_func
(
&
rf_device
,
&
timestamp
,
rxp
,
nb_sample_per_tti
,
0
);
if
(
readBlockSize
!=
nb_sample_per_tti
)
oai_exit
=
1
;
sub_frame
++
;
sub_frame
%=
10
;
if
(
sub_frame
==
0
)
frame_rx
++
;
saif_meas
(
frame_rx
,
sub_frame
);
}
return
(
0
);
}
targets/RT/USER/lte-hwlat2.c
deleted
100644 → 0
View file @
42f8739d
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/* *************************************************************************************************
USER GUIDE
1 - CONFIGURE TEST SESSION
see TESTS PARAMETERS section below
2 - COMPILATION CMD LINE (same as openair compilation)
- NO AVX SUPPORT
/usr/bin/cc -msse4.1 -mssse3 -std=gnu99 -Wall -Wstrict-prototypes -fno-strict-aliasing -rdynamic -funroll-loops -Wno-packed-bitfield-compat -fPIC -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_FCNTL_H=1 -DHAVE_ARPA_INET_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_SYS_SOCKET_H=1 -DHAVE_STRERROR=1 -DHAVE_SOCKET=1 -DHAVE_MEMSET=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_STDLIB_H=1 -DHAVE_MALLOC=1 -DHAVE_LIBSCTP -g -DMALLOC_CHECK_=3 -O2 -o lte-hwlat-test lte-hwlat2.c -lrt -lpthread -lm -ldl
- AVX2 Support
/usr/bin/cc -mavx2 -msse4.1 -mssse3 -std=gnu99 -Wall -Wstrict-prototypes -fno-strict-aliasing -rdynamic -funroll-loops -Wno-packed-bitfield-compat -fPIC -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_FCNTL_H=1 -DHAVE_ARPA_INET_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_SYS_SOCKET_H=1 -DHAVE_STRERROR=1 -DHAVE_SOCKET=1 -DHAVE_MEMSET=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_STDLIB_H=1 -DHAVE_MALLOC=1 -DHAVE_LIBSCTP -g -DMALLOC_CHECK_=3 -O2 -o lte-hwlat-test lte-hwlat2.c -lrt -lpthread -lm -ldl
3 - RUN
sudo cset shield --force --kthread on -c 1-3 // for 4 cores
sudo cset shield --force --kthread on -c 1-7 // for 8 cores
sudo cset shield ./lte-hwlat-test
4 - remove cset shield
sudo cset shield --reset
***************************************************************************************************/
/* *************************************************************************************************
* TESTS PARAMETERS
*/
#define HWLAT_LOOP_CNT 1000000
/* measurment loop count for each thread*/
#define HWLAT_TTI_SLEEP_US 250
/* usleep duration -> IQ capture simulation (in µ seconds) */
#define RX_NB_TH 6
#define CALIB_RT_INTRUMENTATION 0
/* Laurent Thpmas instrumentation -> see openair2/UTIL/LOG/log.h for full implementation
-> This is a copy and paste implementation in this file for a self contained source */
#define INSTRUMENTATION_LT_RDTSC 1
/* SYRTEM rdtsc instrumentation implementation (see below for more infaormation) */
#define INSTRUMENTATION_SYR_RDTSC 2
/* SYRTEM instrumentation using clock_gettime MONOTONIC */
#define INSTRUMENTATION_SYR_CLOCK_MONO 3
/* SYRTEM instrumentation using clock_gettime REALTIME */
#define INSTRUMENTATION_SYR_CLOCK_REALTIME 4
#define HWLAT_INSTRUMENTATION INSTRUMENTATION_LT_RDTSC
/* Statistics histogram output */
#define HISTOGRAM_MIN_VALUE 0
#define HISTOGRAM_MAX_VALUE 2000
#define HISTOGRAM_STEP 1
#define HISTOGRAM_SIZE ( ( ( HISTOGRAM_MAX_VALUE - HISTOGRAM_MIN_VALUE ) / HISTOGRAM_STEP ) + 1 )
/* *************************************************************************************************/
/*
* INCLUDES
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <syscall.h>
#include <math.h>
#include <sched.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sched.h>
#include <linux/sched.h>
#include <signal.h>
#include <execinfo.h>
#include <getopt.h>
#include <sys/sysinfo.h>
#include <unistd.h>
#include <sys/syscall.h>
/* For SYS_xxx definitions */
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#include <inttypes.h>
/* From rt_wrapper.h
****************************************************************************************/
#define gettid() syscall(__NR_gettid) // for gettid
/* From common/utils/itti/assertions.h
****************************************************************************************/
# define display_backtrace()
#define _Assert_Exit_ \
{ \
fprintf(stderr, "\nExiting execution\n"); \
display_backtrace(); \
fflush(stdout); \
fflush(stderr); \
exit(EXIT_FAILURE); \
}
#define _Assert_(cOND, aCTION, fORMAT, aRGS...) \
do { \
if (!(cOND)) { \
fprintf(stderr, "\nAssertion ("#cOND") failed!\n" \
"In %s() %s:%d\n" fORMAT, \
__FUNCTION__, __FILE__, __LINE__, ##aRGS); \
aCTION; \
} \
} while(0)
#define AssertFatal(cOND, fORMAT, aRGS...) _Assert_(cOND, _Assert_Exit_, fORMAT, ##aRGS)
/* From "openair1/PHY/TOOLS/time_meas.h"
****************************************************************************************/
double
cpu_freq_GHz
;
typedef
struct
{
long
long
in
;
long
long
diff
;
long
long
diff_now
;
long
long
p_time
;
/*!< \brief absolute process duration */
long
long
diff_square
;
/*!< \brief process duration square */
long
long
max
;
int
trials
;
int
meas_flag
;
}
time_stats_t
;
static
inline
unsigned
long
long
rdtsc_oai
(
void
)
__attribute__
((
always_inline
));
static
inline
unsigned
long
long
rdtsc_oai
(
void
)
{
unsigned
long
long
a
,
d
;
__asm__
volatile
(
"rdtsc"
:
"=a"
(
a
),
"=d"
(
d
));
return
(
d
<<
32
)
|
a
;
}
double
get_cpu_freq_GHz
(
void
);
static
inline
void
reset_meas
(
time_stats_t
*
ts
)
{
ts
->
trials
=
0
;
ts
->
diff
=
0
;
ts
->
diff_now
=
0
;
ts
->
p_time
=
0
;
ts
->
diff_square
=
0
;
ts
->
max
=
0
;
ts
->
meas_flag
=
0
;
}
double
estimate_MHz_syr
(
void
);
static
__inline__
uint64_t
pickCyclesStart
(
void
);
static
__inline__
uint64_t
pickCyclesStop
(
void
);
/* From "openair2/UTIL/LOG/log.h"
****************************************************************************************/
extern
double
cpuf
;
extern
double
cpu_mhz_syr
;
static
__inline__
uint64_t
rdtsc
(
void
)
{
uint64_t
a
,
d
;
__asm__
volatile
(
"rdtsc"
:
"=a"
(
a
),
"=d"
(
d
));
return
(
d
<<
32
)
|
a
;
}
typedef
struct
m
{
uint64_t
iterations
;
uint64_t
sum
;
uint64_t
maxArray
[
11
];
}
Meas
;
static
inline
void
printMeas
(
char
*
txt
,
Meas
*
M
,
int
period
)
{
if
(
M
->
iterations
%
period
==
0
)
{
char
txt2
[
512
];
sprintf
(
txt2
,
"%s avg=%"
PRIu64
" iterations=%"
PRIu64
" max=%"
PRIu64
":%"
PRIu64
":%"
PRIu64
":%"
PRIu64
":%"
PRIu64
":%"
PRIu64
":%"
PRIu64
":%"
PRIu64
":%"
PRIu64
":%"
PRIu64
"
\n
"
,
txt
,
M
->
sum
/
M
->
iterations
,
M
->
iterations
,
M
->
maxArray
[
1
],
M
->
maxArray
[
2
],
M
->
maxArray
[
3
],
M
->
maxArray
[
4
],
M
->
maxArray
[
5
],
M
->
maxArray
[
6
],
M
->
maxArray
[
7
],
M
->
maxArray
[
8
],
M
->
maxArray
[
9
],
M
->
maxArray
[
10
]);
// SYRTEM : just use printf do not include all LOG_X for this test
//#if DISABLE_LOG_X
printf
(
"%s"
,
txt2
);
//#else
// LOG_W(PHY, "%s",txt2);
//#endif
}
}
static
inline
int
cmpint
(
const
void
*
a
,
const
void
*
b
)
{
uint64_t
*
aa
=
(
uint64_t
*
)
a
;
uint64_t
*
bb
=
(
uint64_t
*
)
b
;
return
(
int
)(
*
aa
-*
bb
);
}
static
inline
uint64_t
updateTimes
(
uint64_t
start
,
Meas
*
M
,
int
period
,
char
*
txt
)
{
if
(
start
!=
0
)
{
uint64_t
end
=
rdtsc
();
long
long
diff
=
(
end
-
start
)
/
(
cpuf
*
1000
);
M
->
maxArray
[
0
]
=
diff
;
M
->
sum
+=
diff
;
M
->
iterations
++
;
qsort
(
M
->
maxArray
,
11
,
sizeof
(
uint64_t
),
cmpint
);
// printMeas(txt,M,period); // SYRTEM : Printed only a the end of the measurment loop
return
diff
;
}
return
0
;
}
static
inline
uint64_t
updateTimes_syr
(
uint64_t
start
,
Meas
*
M
,
int
period
,
char
*
txt
)
{
if
(
start
!=
0
)
{
// uint64_t end=rdtsc();
uint64_t
end
=
pickCyclesStop
();
long
long
diff
=
(
long
long
)((
double
)(
end
-
start
)
/
(
cpu_mhz_syr
));
// long long diff=(end-start)/(cpuf*1000);
M
->
maxArray
[
0
]
=
diff
;
M
->
sum
+=
diff
;
M
->
iterations
++
;
qsort
(
M
->
maxArray
,
11
,
sizeof
(
uint64_t
),
cmpint
);
// printMeas(txt,M,period); // SYRTEM : Printed only a the end of the measurment loop
return
diff
;
}
return
0
;
}
#define initRefTimes(a) static __thread Meas a= {0}
#define pickTime(a) uint64_t a=rdtsc()
#define pickTime_syr(a) uint64_t a=pickCyclesStart()
#define readTime(a) a
/*
* DEFINES
*/
#define TIMESPEC_TO_DOUBLE_US( t ) ( ( (double)t.tv_sec * 1000000 ) + ( (double)t.tv_nsec / 1000 ) )
typedef
struct
histo_time
{
double
max
;
unsigned
int
count
;
}
histo_time_t
;
static
void
measure_time
(
struct
timespec
*
start
,
struct
timespec
*
stop
,
uint8_t
START
,
uint16_t
PRINT_INTERVAL
);
static
struct
timespec
get_timespec_diff
(
struct
timespec
*
start
,
struct
timespec
*
stop
);
void
histogram_save_in_csv
(
histo_time_t
*
histo
,
char
*
file_prefix
);
histo_time_t
*
histogram_init
(
histo_time_t
*
histo
);
void
histogram_store_value
(
histo_time_t
*
histo
,
double
value
);
#define FIFO_PRIORITY 40
#define true 1
#define false 0
/*
* STRUCTURES
*/
/* stub of UE_rxtx_proc full structure in openair1/PHY/defs.h
*/
typedef
struct
UE_rxtx_proc
{
int
instance_cnt_rxtx
;
pthread_t
pthread_rxtx
;
pthread_cond_t
cond_rxtx
;
pthread_mutex_t
mutex_rxtx
;
int
sub_frame_start
;
int
sub_frame_step
;
unsigned
long
long
gotIQs
;
unsigned
long
syr_rdtsc_rxtx_th_unlock_iteration
;
uint64_t
syr_rdtsc_ue_th_got_iq
;
double
syr_rdtsc_rxtx_th_unlock
;
double
syr_rdtsc_rxtx_th_unlock_max
;
double
syr_rdtsc_rxtx_th_unlock_mean
;
double
syr_rdtsc_rxtx_th_unlock_min
;
histo_time_t
*
syr_rdtsc_rxtx_th_unlock_histogram
;
}
UE_rxtx_proc_t
;
/* this structure is used to pass both UE phy vars and
* proc to the function UE_thread_rxn_txnp4
*/
struct
rx_tx_thread_data
{
/* PHY_VARS_UE *UE; */
// UE phy vars not used for this test
UE_rxtx_proc_t
*
proc
;
// We use a stub of rxtx_proc see definition above
};
// ODD / EVEN Scheduling
#if 0
typedef struct threads_s {
int iq;
int odd;
int even;
} threads_t;
threads_t threads = { -1, -1, -1 }; // Core number for each thread (iq=3, even=2, odd=1)
#endif
// SLOT 0 / SLOT 1 parallelization
typedef
struct
threads_s
{
int
iq
;
int
one
;
int
two
;
int
three
;
int
four
;
int
five
;
int
six
;
int
slot1_proc_one
;
int
slot1_proc_two
;
int
slot1_proc_three
;
}
threads_t
;
threads_t
threads
=
{
7
,
6
,
5
,
4
,
3
,
2
,
1
,
-
1
,
-
1
,
-
1
};
/*
* FUNCTIONS DEFINITION
*/
void
*
UE_thread
(
void
*
arg
);
void
init_UE
(
int
nb_inst
);
/*
* GLOBALS VARIABLES
*/
volatile
int
oai_exit
=
0
;
int
th_count
=
0
;
double
cpuf
;
double
cpu_mhz_syr
;
pthread_t
pthread_ue
;
pthread_attr_t
attr_ue
;
UE_rxtx_proc_t
**
rxtx_proc
;
struct
timespec
even_start
,
even_stop
;
struct
timespec
odd_start
,
odd_stop
;
histo_time_t
*
th_wake_histogram
;
/*
* FUNCTIONS
*/
void
exit_fun
(
const
char
*
s
)
{
if
(
s
!=
NULL
)
{
printf
(
"%s %s() Exiting OAI softmodem: %s
\n
"
,
__FILE__
,
__FUNCTION__
,
s
);
}
oai_exit
=
1
;
}
void
init_thread
(
int
sched_runtime
,
int
sched_deadline
,
int
sched_fifo
,
cpu_set_t
*
cpuset
,
char
*
name
)
{
#ifdef DEADLINE_SCHEDULER
if
(
sched_runtime
!=
0
)
{
struct
sched_attr
attr
=
{
0
};
attr
.
size
=
sizeof
(
attr
);
attr
.
sched_policy
=
SCHED_DEADLINE
;
attr
.
sched_runtime
=
sched_runtime
;
attr
.
sched_deadline
=
sched_deadline
;
attr
.
sched_period
=
0
;
AssertFatal
(
sched_setattr
(
0
,
&
attr
,
0
)
==
0
,
"[SCHED] %s thread: sched_setattr failed %s
\n
"
,
name
,
strerror
(
errno
));
LOG_I
(
HW
,
"[SCHED][eNB] %s deadline thread %lu started on CPU %d
\n
"
,
name
,
(
unsigned
long
)
gettid
(),
sched_getcpu
());
}
#else
if
(
CPU_COUNT
(
cpuset
)
>
0
)
AssertFatal
(
0
==
pthread_setaffinity_np
(
pthread_self
(),
sizeof
(
cpu_set_t
),
cpuset
),
""
);
struct
sched_param
sp
;
sp
.
sched_priority
=
sched_fifo
;
AssertFatal
(
pthread_setschedparam
(
pthread_self
(),
SCHED_FIFO
,
&
sp
)
==
0
,
"Can't set thread priority, Are you root?
\n
"
);
/* Check the actual affinity mask assigned to the thread */
cpu_set_t
*
cset
=
CPU_ALLOC
(
CPU_SETSIZE
);
if
(
0
==
pthread_getaffinity_np
(
pthread_self
(),
CPU_ALLOC_SIZE
(
CPU_SETSIZE
),
cset
))
{
char
txt
[
512
]
=
{
0
};
for
(
int
j
=
0
;
j
<
CPU_SETSIZE
;
j
++
)
if
(
CPU_ISSET
(
j
,
cset
))
sprintf
(
txt
+
strlen
(
txt
),
" %d "
,
j
);
printf
(
"CPU Affinity of thread %s is %s
\n
"
,
name
,
txt
);
}
CPU_FREE
(
cset
);
#endif
// Lock memory from swapping. This is a process wide call (not constraint to this thread).
mlockall
(
MCL_CURRENT
|
MCL_FUTURE
);
pthread_setname_np
(
pthread_self
(),
name
);
// SYRTEM : Synchronization thread is not simulated -> just ignore this part of code
// // LTS: this sync stuff should be wrong
// printf("waiting for sync (%s)\n",name);
// pthread_mutex_lock(&sync_mutex);
// printf("Locked sync_mutex, waiting (%s)\n",name);
// while (sync_var<0)
// pthread_cond_wait(&sync_cond, &sync_mutex);
// pthread_mutex_unlock(&sync_mutex);
printf
(
"started %s as PID: %ld
\n
"
,
name
,
gettid
());
}
void
init_UE
(
int
nb_inst
)
{
int
inst
;
for
(
inst
=
0
;
inst
<
nb_inst
;
inst
++
)
{
// UE->rfdevice.type = NONE_DEV;
// SYRTEM : we use a stub of phy_var_ue
// PHY_VARS_UE *UE = PHY_vars_UE_g[inst][0];
// AssertFatal(0 == pthread_create(&UE->proc.pthread_ue, &UE->proc.attr_ue, UE_thread, (void*)UE), "");
AssertFatal
(
0
==
pthread_create
(
&
pthread_ue
,
&
attr_ue
,
UE_thread
,
NULL
),
""
);
}
printf
(
"UE threads created by %ld
\n
"
,
gettid
());
}
// SYRTEM - UE synchronization thread is not used in this latency test program
//static void *UE_thread_synch(void *arg) {
// ...
//}
// SYRTEM - Stub of UE_thread_rxn_txnp4
// -> No DSP scheduled
// -> Only thread initialization and thread wake up are kept
static
void
*
UE_thread_rxn_txnp4
(
void
*
arg
){
static
__thread
int
UE_thread_rxtx_retval
;
struct
rx_tx_thread_data
*
rtd
=
arg
;
UE_rxtx_proc_t
*
proc
=
rtd
->
proc
;
proc
->
instance_cnt_rxtx
=-
1
;
char
threadname
[
256
];
sprintf
(
threadname
,
"UE_%d_proc_%d"
,
0
,
proc
->
sub_frame_start
);
cpu_set_t
cpuset
;
CPU_ZERO
(
&
cpuset
);
if
(
(
proc
->
sub_frame_start
)
%
RX_NB_TH
==
0
&&
threads
.
one
!=
-
1
)
CPU_SET
(
threads
.
one
,
&
cpuset
);
if
(
(
proc
->
sub_frame_start
)
%
RX_NB_TH
==
1
&&
threads
.
two
!=
-
1
)
CPU_SET
(
threads
.
two
,
&
cpuset
);
if
(
(
proc
->
sub_frame_start
)
%
RX_NB_TH
==
2
&&
threads
.
three
!=
-
1
)
CPU_SET
(
threads
.
three
,
&
cpuset
);
if
(
(
proc
->
sub_frame_start
)
%
RX_NB_TH
==
3
&&
threads
.
four
!=
-
1
)
CPU_SET
(
threads
.
four
,
&
cpuset
);
if
(
(
proc
->
sub_frame_start
)
%
RX_NB_TH
==
4
&&
threads
.
five
!=
-
1
)
CPU_SET
(
threads
.
five
,
&
cpuset
);
if
(
(
proc
->
sub_frame_start
)
%
RX_NB_TH
==
5
&&
threads
.
six
!=
-
1
)
CPU_SET
(
threads
.
six
,
&
cpuset
);
//CPU_SET(threads.three, &cpuset);
init_thread
(
900000
,
1000000
,
FIFO_PRIORITY
-
1
,
&
cpuset
,
threadname
);
proc
->
syr_rdtsc_rxtx_th_unlock_iteration
=
0
;
proc
->
syr_rdtsc_rxtx_th_unlock_max
=
0
;
proc
->
syr_rdtsc_rxtx_th_unlock_mean
=
0
;
proc
->
syr_rdtsc_rxtx_th_unlock_min
=
1000
;
proc
->
syr_rdtsc_rxtx_th_unlock_histogram
=
NULL
;
proc
->
syr_rdtsc_rxtx_th_unlock_histogram
=
histogram_init
(
proc
->
syr_rdtsc_rxtx_th_unlock_histogram
);
while
(
!
oai_exit
)
{
if
(
pthread_mutex_lock
(
&
proc
->
mutex_rxtx
)
!=
0
)
{
printf
(
"[SCHED][UE] error locking mutex for UE RXTX
\n
"
);
exit_fun
(
"nothing to add"
);
}
while
(
proc
->
instance_cnt_rxtx
<
0
)
{
// most of the time, the thread is waiting here
pthread_cond_wait
(
&
proc
->
cond_rxtx
,
&
proc
->
mutex_rxtx
);
}
if
(
pthread_mutex_unlock
(
&
proc
->
mutex_rxtx
)
!=
0
)
{
printf
(
"[SCHED][UE] error unlocking mutex for UE RXn_TXnp4
\n
"
);
exit_fun
(
"nothing to add"
);
}
proc
->
syr_rdtsc_rxtx_th_unlock
=
(
double
)(
pickCyclesStop
()
-
proc
->
syr_rdtsc_ue_th_got_iq
)
/
cpu_mhz_syr
;
proc
->
syr_rdtsc_rxtx_th_unlock_iteration
++
;
proc
->
syr_rdtsc_rxtx_th_unlock_mean
+=
proc
->
syr_rdtsc_rxtx_th_unlock
;
if
(
proc
->
syr_rdtsc_rxtx_th_unlock_max
<
proc
->
syr_rdtsc_rxtx_th_unlock
)
proc
->
syr_rdtsc_rxtx_th_unlock_max
=
proc
->
syr_rdtsc_rxtx_th_unlock
;
if
(
proc
->
syr_rdtsc_rxtx_th_unlock_min
>
proc
->
syr_rdtsc_rxtx_th_unlock
)
proc
->
syr_rdtsc_rxtx_th_unlock_min
=
proc
->
syr_rdtsc_rxtx_th_unlock
;
histogram_store_value
(
proc
->
syr_rdtsc_rxtx_th_unlock_histogram
,
proc
->
syr_rdtsc_rxtx_th_unlock
);
if
(
pthread_mutex_lock
(
&
proc
->
mutex_rxtx
)
!=
0
)
{
printf
(
"[SCHED][UE] error locking mutex for UE RXTX
\n
"
);
exit_fun
(
"noting to add"
);
}
proc
->
instance_cnt_rxtx
--
;
if
(
pthread_mutex_unlock
(
&
proc
->
mutex_rxtx
)
!=
0
)
{
printf
(
"[SCHED][UE] error unlocking mutex for UE RXTX
\n
"
);
exit_fun
(
"noting to add"
);
}
}
// thread finished
free
(
arg
);
return
&
UE_thread_rxtx_retval
;
}
void
*
UE_thread
(
void
*
arg
)
{
int
i
=
0
;
int
hw_loop_cnt
=
0
;
int
nb_threads
=
RX_NB_TH
;
char
threadname
[
128
];
cpu_set_t
cpuset
;
struct
rx_tx_thread_data
*
rtd
;
UE_rxtx_proc_t
*
proc
;
CPU_ZERO
(
&
cpuset
);
if
(
threads
.
iq
!=
-
1
)
CPU_SET
(
threads
.
iq
,
&
cpuset
);
init_thread
(
100000
,
500000
,
FIFO_PRIORITY
,
&
cpuset
,
"HDW Threads"
);
sprintf
(
threadname
,
"Main UE %d"
,
0
);
pthread_setname_np
(
pthread_self
(),
threadname
);
// init_UE_threads(UE)
pthread_attr_init
(
&
attr_ue
);
pthread_attr_setstacksize
(
&
attr_ue
,
8192
);
//5*PTHREAD_STACK_MIN);
for
(
i
=
0
;
i
<
nb_threads
;
i
++
)
{
printf
(
"
\n
"
);
rtd
=
calloc
(
1
,
sizeof
(
struct
rx_tx_thread_data
)
);
if
(
rtd
==
NULL
)
abort
();
rtd
->
proc
=
rxtx_proc
[
i
];
// &UE->proc.proc_rxtx[i];
pthread_mutex_init
(
&
rxtx_proc
[
i
]
->
mutex_rxtx
,
NULL
);
// pthread_mutex_init( &UE->proc.proc_rxtx[i].mutex_rxtx,NULL );
pthread_cond_init
(
&
rxtx_proc
[
i
]
->
cond_rxtx
,
NULL
);
// pthread_cond_init(&UE->proc.proc_rxtx[i].cond_rxtx,NULL);
rtd
->
proc
->
sub_frame_start
=
i
;
rtd
->
proc
->
sub_frame_step
=
nb_threads
;
printf
(
"Init_UE_threads rtd %d proc %d nb_threads %d i %d
\n
"
,
rtd
->
proc
->
sub_frame_start
,
rxtx_proc
[
i
]
->
sub_frame_start
,
nb_threads
,
i
);
pthread_create
(
&
rxtx_proc
[
i
]
->
pthread_rxtx
,
NULL
,
UE_thread_rxn_txnp4
,
rtd
);
// pthread_create( &UE->proc.proc_rxtx[i].pthread_rxtx, NULL, UE_thread_rxn_txnp4, rtd);
usleep
(
1000
);
}
// init_UE_threads(UE)
int
sub_frame
=-
1
;
while
(
!
oai_exit
)
{
sub_frame
++
;
sub_frame
%=
10
;
proc
=
rxtx_proc
[
hw_loop_cnt
%
RX_NB_TH
];
// Simulate IQ reception
usleep
(
HWLAT_TTI_SLEEP_US
);
proc
->
syr_rdtsc_ue_th_got_iq
=
pickCyclesStart
();
AssertFatal
(
pthread_mutex_lock
(
&
proc
->
mutex_rxtx
)
==
0
,
""
);
proc
->
instance_cnt_rxtx
++
;
if
(
proc
->
instance_cnt_rxtx
==
0
)
{
if
(
pthread_cond_signal
(
&
proc
->
cond_rxtx
)
!=
0
)
{
exit_fun
(
"nothing to add"
);
}
}
else
{
if
(
proc
->
instance_cnt_rxtx
>
2
)
exit_fun
(
"instance_cnt_rxtx > 2"
);
}
AssertFatal
(
pthread_cond_signal
(
&
proc
->
cond_rxtx
)
==
0
,
""
);
AssertFatal
(
pthread_mutex_unlock
(
&
proc
->
mutex_rxtx
)
==
0
,
""
);
/* Do not go indefinitely */
hw_loop_cnt
++
;
if
(
hw_loop_cnt
%
1000
==
0
)
{
printf
(
"
\r
%d/%d"
,
hw_loop_cnt
,
HWLAT_LOOP_CNT
*
RX_NB_TH
);
fflush
(
stdout
);
}
if
(
hw_loop_cnt
>=
HWLAT_LOOP_CNT
*
RX_NB_TH
)
{
printf
(
"
\n\n
"
);
for
(
i
=
0
;
i
<
RX_NB_TH
;
i
++
)
{
proc
=
rxtx_proc
[
i
];
pthread_getname_np
(
proc
->
pthread_rxtx
,
threadname
,
128
);
printf
(
"RxTX Thread unlock latency on thread %s (it. %lu) (us) : max=%8.3f - mean=%8.3f - min=%8.3f
\n
"
,
threadname
,
proc
->
syr_rdtsc_rxtx_th_unlock_iteration
,
proc
->
syr_rdtsc_rxtx_th_unlock_max
,
proc
->
syr_rdtsc_rxtx_th_unlock_mean
/
proc
->
syr_rdtsc_rxtx_th_unlock_iteration
,
proc
->
syr_rdtsc_rxtx_th_unlock_min
);
histogram_save_in_csv
(
proc
->
syr_rdtsc_rxtx_th_unlock_histogram
,
threadname
);
}
printf
(
"
\n\n
"
);
oai_exit
=
1
;
}
}
// while !oai_exit
oai_exit
=
1
;
return
NULL
;
}
#define CALIB_LOOP_CNT 1000000 //2000000000
#define CALIB_LOOP_REPORT_PERIOD 1000
#define CALIB_LOOP_UP_THRESHOLD 20 // 20 -> for NG Intel flat model
#define CALIB_USLEEP 250
int
main
(
void
)
{
int
i
;
#if CALIB_RT_INTRUMENTATION
uint32_t
calib_loop_count
;
uint64_t
lt_overhead_cur
;
uint64_t
lt_overhead_min
;
uint64_t
lt_overhead_max
;
uint64_t
lt_overhead_mean
;
histo_time_t
*
lt_overhead_histogram
=
NULL
;
uint64_t
lt_syr_overhead_cur
;
uint64_t
lt_syr_overhead_min
;
uint64_t
lt_syr_overhead_max
;
uint64_t
lt_syr_overhead_mean
;
histo_time_t
*
lt_syr_overhead_histogram
=
NULL
;
double
syr_rdtsc_overhead_cur
;
double
syr_rdtsc_overhead_min
;
double
syr_rdtsc_overhead_max
;
double
syr_rdtsc_overhead_mean
;
histo_time_t
*
syr_rdtsc_overhead_histogram
=
NULL
;
double
syr_clock_gettime_overhead_cur
;
double
syr_clock_gettime_overhead_min
;
double
syr_clock_gettime_overhead_max
;
double
syr_clock_gettime_overhead_mean
;
histo_time_t
*
syr_clock_gettime_overhead_histogram
=
NULL
;
uint64_t
cycles_start
;
uint64_t
cycles_stop
;
uint64_t
cycles_diff
;
uint64_t
cycles_diff_max
=
0
;
struct
timespec
start
;
struct
timespec
stop
;
#endif
cpuf
=
get_cpu_freq_GHz
();
cpu_mhz_syr
=
estimate_MHz_syr
();
printf
(
"
\n\n
cpuf %f - cpu_mhz_syr %f
\n\n
"
,
cpuf
,
cpu_mhz_syr
);
#if CALIB_RT_INTRUMENTATION
/* ********************************************************************************************** */
/* CALIBRATION */
/* ********************************************************************************************** */
/* *************************************************************
Laurent Thomas instrumentation overhead
*/
printf
(
"
\n
Calibrating OAI Realtime Instrumentation (Laurent Thomas imp.)
\n
"
);
calib_loop_count
=
CALIB_LOOP_CNT
;
initRefTimes
(
lt_instru_calib
);
// Laurent Thomas realtime instrumentation calibration measurments
lt_overhead_min
=
1000
;
lt_overhead_max
=
0
;
lt_overhead_mean
=
0
;
lt_overhead_histogram
=
histogram_init
(
lt_overhead_histogram
);
while
(
calib_loop_count
)
{
pickTime
(
lt_start
);
// asm volatile(""); // Nop instruction
usleep
(
CALIB_USLEEP
);
lt_overhead_cur
=
updateTimes
(
readTime
(
lt_start
),
&
lt_instru_calib
,
CALIB_LOOP_CNT
,
"Laurent Thomas realtime instrumentation calibration measurments"
);
lt_overhead_mean
+=
lt_overhead_cur
;
if
(
lt_overhead_max
<
lt_overhead_cur
)
lt_overhead_max
=
lt_overhead_cur
;
if
(
lt_overhead_min
>
lt_overhead_cur
)
lt_overhead_min
=
lt_overhead_cur
;
histogram_store_value
(
lt_overhead_histogram
,
(
double
)
lt_overhead_cur
);
if
(
calib_loop_count
%
CALIB_LOOP_REPORT_PERIOD
==
0
)
{
printf
(
"
\r
%d/%d"
,
calib_loop_count
,
CALIB_LOOP_CNT
);
fflush
(
stdout
);
}
calib_loop_count
--
;
}
lt_overhead_mean
=
lt_overhead_mean
/
CALIB_LOOP_CNT
;
// printMeas("\nLaurent Thomas realtime instrumentation calibration measurments",<_instru_calib,CALIB_LOOP_CNT);
/* *************************************************************
Laurent Thomas instrumentation overhead
*/
printf
(
"
\n
Calibrating OAI Realtime Instrumentation - SYRTEM revisited
\n
"
);
calib_loop_count
=
CALIB_LOOP_CNT
;
initRefTimes
(
lt_instru_calib_syr
);
// Laurent Thomas realtime instrumentation calibration measurments
lt_syr_overhead_min
=
1000
;
lt_syr_overhead_max
=
0
;
lt_syr_overhead_mean
=
0
;
lt_syr_overhead_histogram
=
histogram_init
(
lt_syr_overhead_histogram
);
while
(
calib_loop_count
)
{
pickTime_syr
(
lt_start_syr
);
// asm volatile(""); // Nop instruction
usleep
(
CALIB_USLEEP
);
lt_syr_overhead_cur
=
updateTimes_syr
(
readTime
(
lt_start_syr
),
&
lt_instru_calib_syr
,
CALIB_LOOP_CNT
,
"Laurent Thomas realtime instrumentation calibration measurments (SYRTEM Update)"
);
lt_syr_overhead_mean
+=
lt_syr_overhead_cur
;
if
(
lt_syr_overhead_max
<
lt_syr_overhead_cur
)
lt_syr_overhead_max
=
lt_syr_overhead_cur
;
if
(
lt_syr_overhead_min
>
lt_syr_overhead_cur
)
lt_syr_overhead_min
=
lt_syr_overhead_cur
;
histogram_store_value
(
lt_syr_overhead_histogram
,
(
double
)
lt_syr_overhead_cur
);
if
(
calib_loop_count
%
CALIB_LOOP_REPORT_PERIOD
==
0
)
{
printf
(
"
\r
%d/%d"
,
calib_loop_count
,
CALIB_LOOP_CNT
);
fflush
(
stdout
);
}
calib_loop_count
--
;
}
lt_syr_overhead_mean
=
lt_syr_overhead_mean
/
CALIB_LOOP_CNT
;
// printMeas("\nLaurent Thomas realtime instrumentation calibration measurments (SYRTEM Update)",<_instru_calib_syr,CALIB_LOOP_CNT);
/* *************************************************************
SYRTEM RDTSC instrumentation overhead
*/
printf
(
"
\n
Calibrating SYRTEM RDTSC Realtime Instrumentation
\n
"
);
calib_loop_count
=
CALIB_LOOP_CNT
;
syr_rdtsc_overhead_min
=
1000
;
syr_rdtsc_overhead_max
=
0
;
syr_rdtsc_overhead_mean
=
0
;
syr_rdtsc_overhead_histogram
=
histogram_init
(
syr_rdtsc_overhead_histogram
);
while
(
calib_loop_count
)
{
cycles_start
=
pickCyclesStart
();
// asm volatile(""); // Nop instruction
usleep
(
CALIB_USLEEP
);
cycles_stop
=
pickCyclesStop
();
cycles_diff
=
cycles_stop
-
cycles_start
;
if
(
cycles_diff_max
<
cycles_diff
)
cycles_diff_max
=
cycles_diff
;
syr_rdtsc_overhead_cur
=
(
double
)
cycles_diff
/
cpu_mhz_syr
;
syr_rdtsc_overhead_mean
+=
syr_rdtsc_overhead_cur
;
if
(
syr_rdtsc_overhead_max
<
syr_rdtsc_overhead_cur
)
syr_rdtsc_overhead_max
=
syr_rdtsc_overhead_cur
;
if
(
syr_rdtsc_overhead_min
>
syr_rdtsc_overhead_cur
)
syr_rdtsc_overhead_min
=
syr_rdtsc_overhead_cur
;
histogram_store_value
(
syr_rdtsc_overhead_histogram
,
(
double
)
syr_rdtsc_overhead_cur
);
if
(
calib_loop_count
%
CALIB_LOOP_REPORT_PERIOD
==
0
)
{
printf
(
"
\r
%d/%d"
,
calib_loop_count
,
CALIB_LOOP_CNT
);
fflush
(
stdout
);
}
calib_loop_count
--
;
}
syr_rdtsc_overhead_mean
=
syr_rdtsc_overhead_mean
/
CALIB_LOOP_CNT
;
// printf("\nSYRTEM RDTSV realtime instrumentation calibration : cycles_diff_max %ld - tsc_duration_max %f us\n ", cycles_diff_max, tsc_duration_max);
/* *************************************************************
SYRTEM Clock_gettime MONOTONIC instrumentation overhead
*/
printf
(
"
\n
Calibrating SYRTEM clock_gettime Realtime Instrumentation
\n
"
);
calib_loop_count
=
CALIB_LOOP_CNT
;
syr_clock_gettime_overhead_min
=
1000
;
syr_clock_gettime_overhead_max
=
0
;
syr_clock_gettime_overhead_mean
=
0
;
syr_clock_gettime_overhead_histogram
=
histogram_init
(
syr_clock_gettime_overhead_histogram
);
while
(
calib_loop_count
)
{
clock_gettime
(
CLOCK_MONOTONIC
,
&
start
);
// asm volatile(""); // Nop instruction
usleep
(
CALIB_USLEEP
);
clock_gettime
(
CLOCK_MONOTONIC
,
&
stop
);
syr_clock_gettime_overhead_cur
=
TIMESPEC_TO_DOUBLE_US
(
get_timespec_diff
(
&
start
,
&
stop
)
);
syr_clock_gettime_overhead_mean
+=
syr_clock_gettime_overhead_cur
;
if
(
syr_clock_gettime_overhead_max
<
syr_clock_gettime_overhead_cur
)
syr_clock_gettime_overhead_max
=
syr_clock_gettime_overhead_cur
;
if
(
syr_clock_gettime_overhead_min
>
syr_clock_gettime_overhead_cur
)
syr_clock_gettime_overhead_min
=
syr_clock_gettime_overhead_cur
;
histogram_store_value
(
syr_clock_gettime_overhead_histogram
,
(
double
)
syr_clock_gettime_overhead_cur
);
if
(
calib_loop_count
%
CALIB_LOOP_REPORT_PERIOD
==
0
)
{
printf
(
"
\r
%d/%d"
,
calib_loop_count
,
CALIB_LOOP_CNT
);
fflush
(
stdout
);
}
calib_loop_count
--
;
}
syr_clock_gettime_overhead_mean
=
syr_clock_gettime_overhead_mean
/
CALIB_LOOP_CNT
;
// printf("\nSYRTEM clock_gettime MONOTONIC calibration : clock_gettime duration_max %f us\n ", max);
printf
(
"
\n
"
);
printf
(
"OAI LT RT profiling overhead (it. %d) (us) : max=%8ld - mean=%8ld - min=%8ld
\n
"
,
CALIB_LOOP_CNT
,
lt_overhead_max
,
lt_overhead_mean
,
lt_overhead_min
);
printf
(
"OAI SYR RT profiling overhead (it. %d) (us) : max=%8ld - mean=%8ld - min=%8ld
\n
"
,
CALIB_LOOP_CNT
,
lt_syr_overhead_max
,
lt_syr_overhead_mean
,
lt_syr_overhead_min
);
printf
(
"SYR RDTSC profiling overhead (it. %d) (us) : max=%8.3f - mean=%8.3f - min=%8.3f
\n
"
,
CALIB_LOOP_CNT
,
syr_rdtsc_overhead_max
,
syr_rdtsc_overhead_mean
,
syr_rdtsc_overhead_min
);
printf
(
"SYR clock_gettime profiling overhead (it. %d) (us): max=%8.3f - mean=%8.3f - min=%8.3f
\n
"
,
CALIB_LOOP_CNT
,
syr_clock_gettime_overhead_max
,
syr_clock_gettime_overhead_mean
,
syr_clock_gettime_overhead_min
);
return
0
;
#endif
rxtx_proc
=
calloc
(
RX_NB_TH
,
sizeof
(
UE_rxtx_proc_t
*
)
);
for
(
i
=
0
;
i
<
RX_NB_TH
;
i
++
)
rxtx_proc
[
i
]
=
calloc
(
1
,
sizeof
(
UE_rxtx_proc_t
)
);
th_wake_histogram
=
histogram_init
(
th_wake_histogram
);
init_UE
(
1
);
while
(
!
oai_exit
)
sleep
(
1
);
return
0
;
}
double
estimate_MHz_syr
(
void
)
{
//copied blantantly from http://www.cs.helsinki.fi/linux/linux-kernel/2001-37/0256.html
/*
* $Id: MHz.c,v 1.4 2001/05/21 18:58:01 davej Exp $
* This file is part of x86info.
* (C) 2001 Dave Jones.
*
* Licensed under the terms of the GNU GPL License version 2.
*
* Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
* Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz>
*
*/
struct
timespec
start
;
struct
timespec
stop
;
unsigned
long
long
int
cycles
[
2
];
/* must be 64 bit */
double
microseconds
;
/* total time taken */
/* get this function in cached memory */
cycles
[
0
]
=
rdtsc
();
clock_gettime
(
CLOCK_REALTIME
,
&
start
);
/* we don't trust that this is any specific length of time */
usleep
(
100000
);
cycles
[
1
]
=
rdtsc
();
clock_gettime
(
CLOCK_REALTIME
,
&
stop
);
microseconds
=
TIMESPEC_TO_DOUBLE_US
(
get_timespec_diff
(
&
start
,
&
stop
)
);
unsigned
long
long
int
elapsed
=
0
;
if
(
cycles
[
1
]
<
cycles
[
0
])
{
//printf("c0 = %llu c1 = %llu",cycles[0],cycles[1]);
elapsed
=
UINT32_MAX
-
cycles
[
0
];
elapsed
=
elapsed
+
cycles
[
1
];
//printf("c0 = %llu c1 = %llu max = %llu elapsed=%llu\n",cycles[0], cycles[1], UINT32_MAX,elapsed);
}
else
{
elapsed
=
cycles
[
1
]
-
cycles
[
0
];
// printf("\nc0 = %llu c1 = %llu elapsed=%llu\n",cycles[0], cycles[1],elapsed);
}
double
mhz
=
elapsed
/
microseconds
;
//printf("%llg MHz processor (estimate). diff cycles=%llu microseconds=%llu \n", mhz, elapsed, microseconds);
//printf("%g elapsed %llu microseconds %llu\n",mhz, elapsed, microseconds);
return
(
mhz
);
}
/** TSC Timestamp references
- http://oliveryang.net/2015/09/pitfalls-of-TSC-usage/#312-tsc-sync-behaviors-on-smp-system
- https://www.intel.com/content/www/us/en/embedded/training/ia-32-ia-64-benchmark-code-execution-paper.html
- https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-3b-part-2-manual.pdf
- http://blog.tinola.com/?e=54
- https://stackoverflow.com/questions/24392392/getting-tsc-frequency-from-proc-cpuinfo !! warning on turbo
- https://gist.github.com/nfarring/1624742
- https://www.lmax.com/blog/staff-blogs/2015/10/25/time-stamp-counters/
- https://github.com/cyring/CoreFreq
- https://patchwork.kernel.org/patch/9438133/ --> TSC_ADJUST - to be checked
-> https://software.intel.com/en-us/forums/software-tuning-performance-optimization-platform-monitoring/topic/388964
- https://www.google.fr/url?sa=t&rct=j&q=&esrc=s&source=web&cd=11&ved=0ahUKEwjwpJbem5DVAhWBDpoKHXv0Dt04ChAWCCIwAA&url=https%3A%2F%2Fsigarra.up.pt%2Ffeup%2Fpt%2Fpub_geral.show_file%3Fpi_gdoc_id%3D809041&usg=AFQjCNFHTMjmjWMG6QSVnLDflEoU0RavKw&cad=rja
- https://unix4lyfe.org/benchmarking/
- https://stackoverflow.com/questions/27693145/rdtscp-versus-rdtsc-cpuid
- https://github.com/dterei/tsc/blob/master/tsc.h
- https://software.intel.com/en-us/forums/intel-isa-extensions/topic/280440
- https://stackoverflow.com/questions/19941588/wrong-clock-cycle-measurements-with-rdtsc
*/
static
__inline__
uint64_t
pickCyclesStart
(
void
)
{
unsigned
cycles_low
,
cycles_high
;
asm
volatile
(
"CPUID
\n\t
"
// serialize
"RDTSC
\n\t
"
// read clock
"MOV %%edx, %0
\n\t
"
"MOV %%eax, %1
\n\t
"
:
"=r"
(
cycles_high
),
"=r"
(
cycles_low
)
::
"%rax"
,
"%rbx"
,
"%rcx"
,
"%rdx"
);
return
((
uint64_t
)
cycles_high
<<
32
)
|
cycles_low
;
}
static
__inline__
uint64_t
pickCyclesStop
(
void
)
{
uint32_t
eax
,
edx
;
__asm__
__volatile__
(
"rdtscp"
:
"=a"
(
eax
),
"=d"
(
edx
)
:
:
"%ecx"
,
"memory"
);
return
(((
uint64_t
)
edx
<<
32
)
|
eax
);
}
/**************************************************************************************
EXTRACT from openair1/PHY/TOOLS/time_meas.c
***************************************************************************************/
double
get_cpu_freq_GHz
(
void
)
{
time_stats_t
ts
=
{
0
};
reset_meas
(
&
ts
);
ts
.
trials
++
;
ts
.
in
=
rdtsc_oai
();
sleep
(
1
);
ts
.
diff
=
(
rdtsc_oai
()
-
ts
.
in
);
cpu_freq_GHz
=
(
double
)
ts
.
diff
/
1000000000
;
printf
(
"CPU Freq is %f
\n
"
,
cpu_freq_GHz
);
return
cpu_freq_GHz
;
}
/**************************************************************************************
SYRTEM STATISTICS HELPER
***************************************************************************************/
histo_time_t
*
histogram_init
(
histo_time_t
*
histo
)
{
int
i
=
0
;
double
max_val
=
HISTOGRAM_MIN_VALUE
+
HISTOGRAM_STEP
;
histo
=
calloc
(
HISTOGRAM_SIZE
,
sizeof
(
histo_time_t
)
);
if
(
histo
==
NULL
)
{
printf
(
"ERROR allocating histogram structure !
\n
"
);
return
NULL
;
}
for
(
i
=
0
;
i
<
HISTOGRAM_SIZE
;
i
++
)
{
histo
[
i
].
max
=
max_val
;
max_val
+=
HISTOGRAM_STEP
;
}
return
histo
;
}
void
histogram_store_value
(
histo_time_t
*
histo
,
double
value
)
{
int
i
=
0
;
for
(
i
=
0
;
i
<
HISTOGRAM_SIZE
;
i
++
)
{
if
(
histo
[
i
].
max
>=
value
||
(
i
+
1
)
==
HISTOGRAM_SIZE
)
{
histo
[
i
].
count
++
;
break
;
}
}
}
void
histogram_save_in_csv
(
histo_time_t
*
histo
,
char
*
file_sufix
)
{
char
*
csv_filename
;
char
month
[
3
],
day
[
3
],
hour
[
3
],
min
[
3
],
sec
[
3
];
time_t
curr_time
;
struct
tm
*
datetime
;
curr_time
=
time
(
NULL
);
datetime
=
localtime
(
&
curr_time
);
csv_filename
=
calloc
(
sizeof
(
char
),
64
);
if
(
csv_filename
==
NULL
)
{
return
;
}
memset
(
csv_filename
,
0x00
,
64
);
memset
(
month
,
0x00
,
3
);
memset
(
day
,
0x00
,
3
);
memset
(
hour
,
0x00
,
3
);
memset
(
min
,
0x00
,
3
);
memset
(
sec
,
0x00
,
3
);
/* Month. */
if
(
datetime
->
tm_mon
<
9
)
snprintf
(
month
,
3
,
"0%d"
,
datetime
->
tm_mon
+
1
);
else
snprintf
(
month
,
3
,
"%d"
,
datetime
->
tm_mon
+
1
);
/* Day. */
if
(
datetime
->
tm_mday
<
10
)
snprintf
(
day
,
3
,
"0%d"
,
datetime
->
tm_mday
);
else
snprintf
(
day
,
3
,
"%d"
,
datetime
->
tm_mday
);
/* Hour. */
if
(
datetime
->
tm_hour
<
10
)
snprintf
(
hour
,
3
,
"0%d"
,
datetime
->
tm_hour
);
else
snprintf
(
hour
,
3
,
"%d"
,
datetime
->
tm_hour
);
/* Minute. */
if
(
datetime
->
tm_min
<
10
)
snprintf
(
min
,
3
,
"0%d"
,
datetime
->
tm_min
);
else
snprintf
(
min
,
3
,
"%d"
,
datetime
->
tm_min
);
/* Second. */
if
(
datetime
->
tm_sec
<
10
)
snprintf
(
sec
,
3
,
"0%d"
,
datetime
->
tm_sec
);
else
snprintf
(
sec
,
3
,
"%d"
,
datetime
->
tm_sec
);
snprintf
(
csv_filename
,
63
,
"ADRV9371_ZC706_HISTO_UEtoRXTX_%d%s%s%s%s%s_%s.csv"
,
datetime
->
tm_year
+
1900
,
month
,
day
,
hour
,
min
,
sec
,
file_sufix
);
FILE
*
fp
;
int
i
=
0
;
int
min_val
=
0
;
fp
=
fopen
(
csv_filename
,
"w+"
);
fprintf
(
fp
,
"range;count
\n
"
);
for
(
i
=
0
;
i
<
HISTOGRAM_SIZE
;
i
++
)
{
if
(
i
+
1
==
HISTOGRAM_SIZE
)
fprintf
(
fp
,
"%d+;%u
\n
"
,
min_val
,
histo
[
i
].
count
);
else
fprintf
(
fp
,
"%d-%.0f;%u
\n
"
,
min_val
,
histo
[
i
].
max
,
histo
[
i
].
count
);
min_val
=
histo
[
i
].
max
;
}
free
(
csv_filename
);
fclose
(
fp
);
}
static
struct
timespec
get_timespec_diff
(
struct
timespec
*
start
,
struct
timespec
*
stop
)
{
struct
timespec
result
;
if
(
(
stop
->
tv_nsec
-
start
->
tv_nsec
)
<
0
)
{
result
.
tv_sec
=
stop
->
tv_sec
-
start
->
tv_sec
-
1
;
result
.
tv_nsec
=
stop
->
tv_nsec
-
start
->
tv_nsec
+
1000000000
;
}
else
{
result
.
tv_sec
=
stop
->
tv_sec
-
start
->
tv_sec
;
result
.
tv_nsec
=
stop
->
tv_nsec
-
start
->
tv_nsec
;
}
return
result
;
}
static
void
measure_time
(
struct
timespec
*
start
,
struct
timespec
*
stop
,
uint8_t
START
,
uint16_t
PRINT_INTERVAL
)
{
static
double
max
=
0
;
static
double
min
=
0
;
static
double
total
=
0
;
static
int
count
=
0
;
if
(
START
)
{
clock_gettime
(
CLOCK_REALTIME
,
start
);
}
else
{
clock_gettime
(
CLOCK_REALTIME
,
stop
);
struct
timespec
diff
;
double
current
=
0
;
diff
=
get_timespec_diff
(
start
,
stop
);
// current = ( (double)diff.tv_sec * 1000000 ) + ( (double)diff.tv_nsec / 1000 );
current
=
TIMESPEC_TO_DOUBLE_US
(
diff
);
if
(
current
>
max
)
{
max
=
current
;
}
if
(
min
==
0
||
current
<
min
)
{
min
=
current
;
}
total
+=
current
;
histogram_store_value
(
th_wake_histogram
,
current
);
if
(
count
%
PRINT_INTERVAL
==
0
&&
count
!=
0
)
{
double
avg
=
total
/
(
count
+
1
);
printf
(
"[%d] Current : %.2lf µs, Min : %.2lf µs, Max : %.2lf µs, Moy : %.2lf µs
\n
"
,
count
,
current
,
min
,
max
,
avg
);
}
count
++
;
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment