#define FASTRPC_LINK_CONNECTED (0x3)
#define FASTRPC_LINK_DISCONNECTING (0x7)
+#define PERF_KEYS "count:flush:map:copy:glink:getargs:putargs:invalidate:invoke"
+#define FASTRPC_STATIC_HANDLE_LISTENER (3)
+#define FASTRPC_STATIC_HANDLE_MAX (20)
+
+#define PERF_END (void)0
+
+#define PERF(enb, cnt, ff) \
+ {\
+ struct timespec startT = {0};\
+ if (enb) {\
+ getnstimeofday(&startT);\
+ } \
+ ff ;\
+ if (enb) {\
+ cnt += getnstimediff(&startT);\
+ } \
+ }
+
static int fastrpc_glink_open(int cid);
static void fastrpc_glink_close(void *chan, int cid);
uintptr_t attr;
};
+struct fastrpc_perf {
+ int64_t count;
+ int64_t flush;
+ int64_t map;
+ int64_t copy;
+ int64_t link;
+ int64_t getargs;
+ int64_t putargs;
+ int64_t invargs;
+ int64_t invoke;
+};
+
struct fastrpc_file {
struct hlist_node hn;
spinlock_t hlock;
struct fastrpc_session_ctx *sctx;
struct fastrpc_session_ctx *secsctx;
uint32_t mode;
+ uint32_t profile;
int tgid;
int cid;
int ssrcount;
int pd;
struct fastrpc_apps *apps;
+ struct fastrpc_perf perf;
};
static struct fastrpc_apps gfa;
},
};
+static inline int64_t getnstimediff(struct timespec *start)
+{
+ int64_t ns;
+ struct timespec ts, b;
+
+ getnstimeofday(&ts);
+ b = timespec_sub(ts, *start);
+ ns = timespec_to_ns(&b);
+ return ns;
+}
+
static void fastrpc_buf_free(struct fastrpc_buf *buf, int cache)
{
struct fastrpc_file *fl = buf == 0 ? 0 : buf->fl;
ipage++;
}
/* map ion buffers */
+ PERF(ctx->fl->profile, ctx->fl->perf.map,
for (i = 0; i < inbufs + outbufs; ++i) {
struct fastrpc_mmap *map = ctx->maps[i];
uint64_t buf = ptr_to_uint64(lpra[i].buf.pv);
}
rpra[i].buf.pv = buf;
}
+ PERF_END);
+
/* copy non ion buffers */
+ PERF(ctx->fl->profile, ctx->fl->perf.copy,
rlen = copylen - metalen;
for (oix = 0; oix < inbufs + outbufs; ++oix) {
int i = ctx->overps[oix]->raix;
args = args + mlen;
rlen -= mlen;
}
+ PERF_END);
+ PERF(ctx->fl->profile, ctx->fl->perf.flush,
for (oix = 0; oix < inbufs + outbufs; ++oix) {
int i = ctx->overps[oix]->raix;
struct fastrpc_mmap *map = ctx->maps[i];
dmac_flush_range(uint64_to_ptr(rpra[i].buf.pv),
uint64_to_ptr(rpra[i].buf.pv + rpra[i].buf.len));
}
+ PERF_END);
+
inh = inbufs + outbufs;
for (i = 0; i < REMOTE_SCALARS_INHANDLES(sc); i++) {
rpra[inh + i].buf.pv = ptr_to_uint64(ctx->lpra[inh + i].buf.pv);
rpra[inh + i].buf.len = ctx->lpra[inh + i].buf.len;
rpra[inh + i].h = ctx->lpra[inh + i].h;
}
- if (!ctx->fl->sctx->smmu.coherent)
+
+ if (!ctx->fl->sctx->smmu.coherent) {
+ PERF(ctx->fl->profile, ctx->fl->perf.flush,
dmac_flush_range((char *)rpra, (char *)rpra + ctx->used);
+ PERF_END);
+ }
bail:
return err;
}
int cid = fl->cid;
int interrupted = 0;
int err = 0;
+ struct timespec invoket;
+ if (fl->profile)
+ getnstimeofday(&invoket);
if (!kernel) {
VERIFY(err, 0 == context_restore_interrupted(fl, inv,
&ctx));
goto bail;
if (REMOTE_SCALARS_LENGTH(ctx->sc)) {
+ PERF(fl->profile, fl->perf.getargs,
VERIFY(err, 0 == get_args(kernel, ctx));
+ PERF_END);
if (err)
goto bail;
}
+ PERF(fl->profile, fl->perf.invargs,
inv_args_pre(ctx);
if (mode == FASTRPC_MODE_SERIAL)
inv_args(ctx);
+ PERF_END);
+
+ PERF(fl->profile, fl->perf.link,
VERIFY(err, 0 == fastrpc_invoke_send(ctx, kernel, invoke->handle));
+ PERF_END);
+
if (err)
goto bail;
+
+ PERF(fl->profile, fl->perf.invargs,
if (mode == FASTRPC_MODE_PARALLEL)
inv_args(ctx);
+ PERF_END);
wait:
if (kernel)
wait_for_completion(&ctx->work);
VERIFY(err, 0 == (err = ctx->retval));
if (err)
goto bail;
+
+ PERF(fl->profile, fl->perf.putargs,
VERIFY(err, 0 == put_args(kernel, ctx, invoke->pra));
+ PERF_END);
if (err)
goto bail;
bail:
context_free(ctx);
if (fl->ssrcount != fl->apps->channel[cid].ssrcount)
err = ECONNRESET;
+
+ if (fl->profile && !interrupted) {
+ if (invoke->handle != FASTRPC_STATIC_HANDLE_LISTENER)
+ fl->perf.invoke += getnstimediff(&invoket);
+ if (!(invoke->handle >= 0 &&
+ invoke->handle <= FASTRPC_STATIC_HANDLE_MAX))
+ fl->perf.count++;
+ }
return err;
}
fl->tgid = current->tgid;
fl->apps = me;
fl->cid = cid;
+ memset(&fl->perf, 0, sizeof(fl->perf));
+
VERIFY(err, !fastrpc_session_alloc_locked(&me->channel[cid], 0,
&fl->sctx));
if (err)
struct fastrpc_ioctl_mmap mmap;
struct fastrpc_ioctl_munmap munmap;
struct fastrpc_ioctl_init init;
+ struct fastrpc_ioctl_perf perf;
} p;
void *param = (char *)ioctl_param;
struct fastrpc_file *fl = (struct fastrpc_file *)file->private_data;
case FASTRPC_MODE_SERIAL:
fl->mode = (uint32_t)ioctl_param;
break;
+ case FASTRPC_MODE_PROFILE:
+ fl->profile = (uint32_t)ioctl_param;
+ break;
default:
err = -ENOTTY;
break;
}
break;
+ case FASTRPC_IOCTL_GETPERF:
+ VERIFY(err, 0 == copy_from_user(&p.perf,
+ param, sizeof(p.perf)));
+ if (err)
+ goto bail;
+ p.perf.numkeys = sizeof(struct fastrpc_perf)/sizeof(int64_t);
+ if (p.perf.keys) {
+ char *keys = PERF_KEYS;
+
+ VERIFY(err, 0 == copy_to_user((char *)p.perf.keys,
+ keys, strlen(keys)+1));
+ if (err)
+ goto bail;
+ }
+ if (p.perf.data) {
+ VERIFY(err, 0 == copy_to_user((int64_t *)p.perf.data,
+ &fl->perf, sizeof(fl->perf)));
+ }
+ VERIFY(err, 0 == copy_to_user(param, &p.perf, sizeof(p.perf)));
+ if (err)
+ goto bail;
+ break;
case FASTRPC_IOCTL_GETINFO:
VERIFY(err, 0 == (err = fastrpc_get_info(fl, &info)));
if (err)
/*
- * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2017, 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
_IOWR('R', 6, struct compat_fastrpc_ioctl_init)
#define COMPAT_FASTRPC_IOCTL_INVOKE_ATTRS \
_IOWR('R', 7, struct compat_fastrpc_ioctl_invoke_attrs)
+#define COMPAT_FASTRPC_IOCTL_GETPERF \
+ _IOWR('R', 9, struct compat_fastrpc_ioctl_perf)
struct compat_remote_buf {
compat_uptr_t pv; /* buffer pointer */
compat_int_t memfd; /* ION fd for the mem */
};
+struct compat_fastrpc_ioctl_perf { /* kernel performance data */
+ compat_uptr_t data;
+ compat_int_t numkeys;
+ compat_uptr_t keys;
+};
+
static int compat_get_fastrpc_ioctl_invoke(
struct compat_fastrpc_ioctl_invoke_attrs __user *inv32,
struct fastrpc_ioctl_invoke_attrs __user **inva,
return err;
}
+static int compat_get_fastrpc_ioctl_perf(
+ struct compat_fastrpc_ioctl_perf __user *perf32,
+ struct fastrpc_ioctl_perf __user *perf)
+{
+ compat_uptr_t p;
+ int err;
+
+ err = get_user(p, &perf32->data);
+ err |= put_user(p, &perf->data);
+ err |= get_user(p, &perf32->keys);
+ err |= put_user(p, &perf->keys);
+
+ return err;
+}
+
static int compat_get_fastrpc_ioctl_init(
struct compat_fastrpc_ioctl_init __user *init32,
struct fastrpc_ioctl_init __user *init)
case FASTRPC_IOCTL_SETMODE:
return filp->f_op->unlocked_ioctl(filp, cmd,
(unsigned long)compat_ptr(arg));
+ case COMPAT_FASTRPC_IOCTL_GETPERF:
+ {
+ struct compat_fastrpc_ioctl_perf __user *perf32;
+ struct fastrpc_ioctl_perf *perf;
+ compat_uint_t u;
+ long ret;
+
+ perf32 = compat_ptr(arg);
+ VERIFY(err, NULL != (perf = compat_alloc_user_space(
+ sizeof(*perf))));
+ if (err)
+ return -EFAULT;
+ VERIFY(err, 0 == compat_get_fastrpc_ioctl_perf(perf32,
+ perf));
+ if (err)
+ return err;
+ ret = filp->f_op->unlocked_ioctl(filp, FASTRPC_IOCTL_GETPERF,
+ (unsigned long)perf);
+ if (ret)
+ return ret;
+ err = get_user(u, &perf->numkeys);
+ err |= put_user(u, &perf32->numkeys);
+ return err;
+ }
default:
return -ENOIOCTLCMD;
}