Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
OpenXG-RAN
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
spbro
OpenXG-RAN
Commits
a0ac75a4
Commit
a0ac75a4
authored
Feb 24, 2022
by
Robert Schmidt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Delete unused files
parent
8a43a030
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 @
8a43a030
/*
* 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 @
8a43a030
/*
* 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