Merge "soc: qcom: hab: add performance test mechanism for HAB"

This commit is contained in:
Linux Build Service Account 2018-06-04 04:30:54 -07:00 committed by Gerrit - the friendly Code Review server
commit c053ae31b8
5 changed files with 286 additions and 2 deletions

View file

@ -10,6 +10,7 @@ msm_hab-objs = \
hab_pipe.o \ hab_pipe.o \
qvm_comm.o \ qvm_comm.o \
hab_qvm.o \ hab_qvm.o \
hab_parser.o hab_parser.o \
khab_test.o
obj-$(CONFIG_MSM_HAB) += msm_hab.o obj-$(CONFIG_MSM_HAB) += msm_hab.o

View file

@ -122,7 +122,7 @@ struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid,
return NULL; return NULL;
} }
static struct hab_device *find_hab_device(unsigned int mm_id) struct hab_device *find_hab_device(unsigned int mm_id)
{ {
int i; int i;

View file

@ -510,6 +510,8 @@ bool hab_is_loopback(void);
int hab_vchan_query(struct uhab_context *ctx, int32_t vcid, uint64_t *ids, int hab_vchan_query(struct uhab_context *ctx, int32_t vcid, uint64_t *ids,
char *names, size_t name_size, uint32_t flags); char *names, size_t name_size, uint32_t flags);
struct hab_device *find_hab_device(unsigned int mm_id);
/* Global singleton HAB instance */ /* Global singleton HAB instance */
extern struct hab_driver hab_driver; extern struct hab_driver hab_driver;

View file

@ -0,0 +1,263 @@
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "hab.h"
#include "khab_test.h"
#include "hab_pipe.h"
#include "hab_qvm.h"
#include <asm/cacheflush.h>
#include <linux/list.h>
static char g_perf_test_result[256];
enum hab_perf_test_type {
HAB_SHMM_THGPUT = 0x0,
};
#define HAB_PERF_TEST_MMID 802
#define PERF_TEST_ITERATION 50
#define MEM_READ_ITERATION 30
static int hab_shmm_throughput_test(void)
{
struct hab_device *habDev;
struct qvm_channel *dev;
struct hab_shared_buf *sh_buf;
struct physical_channel *pchan;
struct timeval tv1, tv2;
int i, counter;
void *test_data;
unsigned char *source_data, *shmm_adr;
register int sum;
register int *pp, *lastone;
int throughput[3][2] = {0};
int latency[6][PERF_TEST_ITERATION];
int ret = 0, tmp, size;
habDev = find_hab_device(HAB_PERF_TEST_MMID);
if (!habDev || list_empty(&(habDev->pchannels))) {
ret = -ENOMEM;
return ret;
}
pchan = list_first_entry(&(habDev->pchannels),
struct physical_channel, node);
dev = pchan->hyp_data;
if (!dev) {
ret = -EPERM;
return ret;
}
sh_buf = dev->pipe_ep->tx_info.sh_buf;
/* pChannel is of 128k, we use 64k to test */
size = 0x10000;
if (!sh_buf) {
pr_err("Share buffer address is empty, exit the perf test\n");
ret = -ENOMEM;
return ret;
}
shmm_adr = sh_buf->data;
test_data = kzalloc(size, GFP_ATOMIC);
if (!test_data) {
ret = -ENOMEM;
return ret;
}
source_data = kzalloc(size, GFP_ATOMIC);
if (!source_data) {
ret = -ENOMEM;
return ret;
}
for (i = 0; i < PERF_TEST_ITERATION; i++) {
/* Normal memory copy latency */
flush_cache_all();
do_gettimeofday(&tv1);
memcpy(test_data, source_data, size);
do_gettimeofday(&tv2);
latency[0][i] = (tv2.tv_sec - tv1.tv_sec)*1000000
+ (tv2.tv_usec - tv1.tv_usec);
/* Share memory copy latency */
flush_cache_all();
do_gettimeofday(&tv1);
memcpy(shmm_adr, source_data, size);
do_gettimeofday(&tv2);
latency[1][i] = (tv2.tv_sec - tv1.tv_sec)*1000000
+ (tv2.tv_usec - tv1.tv_usec);
/* Normal memory read latency */
counter = MEM_READ_ITERATION;
sum = 0;
latency[2][i] = 0;
flush_cache_all();
while (counter-- > 0) {
pp = test_data;
lastone = (int *)((char *)test_data + size - 512);
do_gettimeofday(&tv1);
while (pp <= lastone) {
sum +=
pp[0] + pp[4] + pp[8] + pp[12]
+ pp[16] + pp[20] + pp[24] + pp[28]
+ pp[32] + pp[36] + pp[40] + pp[44]
+ pp[48] + pp[52] + pp[56] + pp[60]
+ pp[64] + pp[68] + pp[72] + pp[76]
+ pp[80] + pp[84] + pp[88] + pp[92]
+ pp[96] + pp[100] + pp[104]
+ pp[108] + pp[112]
+ pp[116] + pp[120]
+ pp[124];
pp += 128;
}
do_gettimeofday(&tv2);
latency[2][i] += (tv2.tv_sec - tv1.tv_sec)*1000000
+ (tv2.tv_usec - tv1.tv_usec);
flush_cache_all();
}
/* Share memory read latency*/
counter = MEM_READ_ITERATION;
sum = 0;
latency[3][i] = 0;
while (counter-- > 0) {
pp = (int *)shmm_adr;
lastone = (int *)(shmm_adr + size - 512);
do_gettimeofday(&tv1);
while (pp <= lastone) {
sum +=
pp[0] + pp[4] + pp[8] + pp[12]
+ pp[16] + pp[20] + pp[24] + pp[28]
+ pp[32] + pp[36] + pp[40] + pp[44]
+ pp[48] + pp[52] + pp[56] + pp[60]
+ pp[64] + pp[68] + pp[72] + pp[76]
+ pp[80] + pp[84] + pp[88] + pp[92]
+ pp[96] + pp[100] + pp[104]
+ pp[108] + pp[112]
+ pp[116] + pp[120]
+ pp[124];
pp += 128;
}
do_gettimeofday(&tv2);
latency[3][i] += (tv2.tv_sec - tv1.tv_sec)*1000000
+ (tv2.tv_usec - tv1.tv_usec);
flush_cache_all();
}
/* Normal memory write latency */
flush_cache_all();
do_gettimeofday(&tv1);
memset(test_data, 'c', size);
do_gettimeofday(&tv2);
latency[4][i] = (tv2.tv_sec - tv1.tv_sec)*1000000
+ (tv2.tv_usec - tv1.tv_usec);
/* Share memory write latency */
flush_cache_all();
do_gettimeofday(&tv1);
memset(shmm_adr, 'c', size);
do_gettimeofday(&tv2);
latency[5][i] = (tv2.tv_sec - tv1.tv_sec)*1000000
+ (tv2.tv_usec - tv1.tv_usec);
}
/* Calculate normal memory copy throughput by average */
tmp = 0;
for (i = 0; i < PERF_TEST_ITERATION; i++)
tmp += latency[0][i];
throughput[0][0] = (tmp != 0) ? size*PERF_TEST_ITERATION/tmp : 0;
/* Calculate share memory copy throughput by average */
tmp = 0;
for (i = 0; i < PERF_TEST_ITERATION; i++)
tmp += latency[1][i];
throughput[0][1] = (tmp != 0) ? size*PERF_TEST_ITERATION/tmp : 0;
/* Calculate normal memory read throughput by average */
tmp = 0;
for (i = 0; i < PERF_TEST_ITERATION; i++)
tmp += latency[2][i];
throughput[1][0] = (tmp != 0) ?
size*PERF_TEST_ITERATION*MEM_READ_ITERATION/tmp : 0;
/* Calculate share memory read throughput by average */
tmp = 0;
for (i = 0; i < PERF_TEST_ITERATION; i++)
tmp += latency[3][i];
throughput[1][1] = (tmp != 0) ?
size*PERF_TEST_ITERATION*MEM_READ_ITERATION/tmp : 0;
/* Calculate normal memory write throughput by average */
tmp = 0;
for (i = 0; i < PERF_TEST_ITERATION; i++)
tmp += latency[4][i];
throughput[2][0] = (tmp != 0) ?
size*PERF_TEST_ITERATION/tmp : 0;
/* Calculate share memory write throughput by average */
tmp = 0;
for (i = 0; i < PERF_TEST_ITERATION; i++)
tmp += latency[5][i];
throughput[2][1] = (tmp != 0) ?
size*PERF_TEST_ITERATION/tmp : 0;
kfree(test_data);
kfree(source_data);
snprintf(g_perf_test_result, sizeof(g_perf_test_result),
"cpy(%d,%d)/read(%d,%d)/write(%d,%d)",
throughput[0][0], throughput[0][1], throughput[1][0],
throughput[1][1], throughput[2][0], throughput[2][1]);
return ret;
}
int hab_perf_test(long testId)
{
int ret;
switch (testId) {
case HAB_SHMM_THGPUT:
ret = hab_shmm_throughput_test();
break;
default:
pr_err("Invalid performance test ID %ld\n", testId);
ret = -EINVAL;
}
return ret;
}
static int kick_hab_perf_test(const char *val, struct kernel_param *kp);
static int get_hab_perf_result(char *buffer, struct kernel_param *kp);
module_param_call(perf_test, kick_hab_perf_test, get_hab_perf_result,
NULL, S_IRUSR | S_IWUSR);
static int kick_hab_perf_test(const char *val, struct kernel_param *kp)
{
long testId;
int err = kstrtol(val, 10, &testId);
if (err)
return err;
memset(g_perf_test_result, 0, sizeof(g_perf_test_result));
return hab_perf_test(testId);
}
static int get_hab_perf_result(char *buffer, struct kernel_param *kp)
{
return strlcpy(buffer, g_perf_test_result,
strlen(g_perf_test_result)+1);
}

View file

@ -0,0 +1,18 @@
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __KHAB_TEST_H
#define __KHAB_TEST_H
int hab_perf_test(long testId);
#endif /* __KHAB_TEST_H */