gpu: nvgpu: create device/context profiler dev nodes

Create new dev nodes for device and context profilers. Example of dev
nodes on iGPU
/dev/nvhost-prof-dev-gpu - device scope profiler
/dev/nvhost-prof-ctx-gpu - context scope profiler

Add below APIs to open/close above dev nodes :
nvgpu_prof_dev_fops_open()
nvgpu_prof_ctx_fops_open()
nvgpu_prof_fops_release()

Add common API nvgpu_prof_fops_ioctl() to handle IOCTL call on these
dev nodes. Add IOCTL NVGPU_PROFILER_IOCTL_BIND_CONTEXT to bind the TSG
to profiler objects.

Add nvgpu_tsg_get_from_file() to retrieve TSG struct pointer from
file descriptor. Also store profiler object pointer into TSG struct.

Enable NVGPU_SUPPORT_PROFILER_V2_DEVICE capability on gv11b and tu104.
Note that this is not yet enabled for vGPU.
Keep NVGPU_SUPPORT_PROFILER_V2_CONTEXT capabiity disabled since this
will take longer to support.

Add new IOCTL NVGPU_PROFILER_IOCTL_UNBIND_CONTEXT so that userspace can
explicitly unbind the context and release the resources before closing
the profiler descriptor.

Add context_init flag to profiler object for book keeping.

Bug 2510974
Jira NVGPU-5360

Change-Id: Ie07e0cfd5a9da9d80008f79c955c7ef93b4bc60f
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2384354
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Deepak Nibade
2020-05-13 11:32:16 +05:30
committed by Alex Waterman
parent fb95b7efa7
commit 969b901999
16 changed files with 437 additions and 5 deletions

View File

@@ -117,6 +117,8 @@ ioctl:
os/linux/ioctl_ctrl.h,
os/linux/ioctl_dbg.c,
os/linux/ioctl_dbg.h,
os/linux/ioctl_prof.c,
os/linux/ioctl_prof.h,
os/linux/ioctl_tsg.c,
os/linux/ioctl_tsg.h ]

View File

@@ -377,6 +377,7 @@ nvgpu-y += \
os/linux/ioctl_channel.o \
os/linux/ioctl_tsg.o \
os/linux/ioctl_dbg.o \
os/linux/ioctl_prof.o \
os/linux/ioctl_clk_arb.o \
os/linux/cond.o \
os/linux/nvgpu_mem.o \

View File

@@ -34,6 +34,9 @@
#include <nvgpu/gr/ctx.h>
#include <nvgpu/runlist.h>
#include <nvgpu/static_analysis.h>
#ifdef CONFIG_NVGPU_PROFILER
#include <nvgpu/profiler.h>
#endif
void nvgpu_tsg_disable(struct nvgpu_tsg *tsg)
{
@@ -808,6 +811,12 @@ void nvgpu_tsg_release_common(struct gk20a *g, struct nvgpu_tsg *tsg)
g->ops.tsg.deinit_eng_method_buffers(g, tsg);
}
#ifdef CONFIG_NVGPU_PROFILER
if (tsg->prof != NULL) {
nvgpu_profiler_unbind_context(tsg->prof);
}
#endif
if (tsg->vm != NULL) {
nvgpu_vm_put(tsg->vm);
tsg->vm = NULL;

View File

@@ -26,6 +26,7 @@
#include <nvgpu/atomic.h>
#include <nvgpu/log.h>
#include <nvgpu/kmem.h>
#include <nvgpu/tsg.h>
static nvgpu_atomic_t unique_id = NVGPU_ATOMIC_INIT(0);
static int generate_unique_id(void)
@@ -68,10 +69,61 @@ void nvgpu_profiler_free(struct nvgpu_profiler_object *prof)
nvgpu_log(g, gpu_dbg_prof, "Free profiler handle %u",
prof->prof_handle);
nvgpu_profiler_unbind_context(prof);
nvgpu_list_del(&prof->prof_obj_entry);
nvgpu_kfree(g, prof);
}
int nvgpu_profiler_bind_context(struct nvgpu_profiler_object *prof,
struct nvgpu_tsg *tsg)
{
struct gk20a *g = prof->g;
nvgpu_log(g, gpu_dbg_prof, "Request to bind tsgid %u with profiler handle %u",
tsg->tsgid, prof->prof_handle);
if (tsg->prof != NULL) {
nvgpu_err(g, "TSG %u is already bound", tsg->tsgid);
return -EINVAL;
}
if (prof->tsg != NULL) {
nvgpu_err(g, "Profiler object %u already bound!", prof->prof_handle);
return -EINVAL;
}
prof->tsg = tsg;
tsg->prof = prof;
nvgpu_log(g, gpu_dbg_prof, "Bind tsgid %u with profiler handle %u successful",
tsg->tsgid, prof->prof_handle);
prof->context_init = true;
return 0;
}
int nvgpu_profiler_unbind_context(struct nvgpu_profiler_object *prof)
{
struct gk20a *g = prof->g;
struct nvgpu_tsg *tsg = prof->tsg;
if (!prof->context_init) {
return -EINVAL;
}
if (tsg != NULL) {
tsg->prof = NULL;
prof->tsg = NULL;
nvgpu_log(g, gpu_dbg_prof, "Unbind profiler handle %u and tsgid %u",
prof->prof_handle, tsg->tsgid);
}
prof->context_init = false;
return 0;
}
int nvgpu_profiler_pm_resource_reserve(struct nvgpu_profiler_object *prof,
enum nvgpu_profiler_pm_resource_type pm_resource)
{

View File

@@ -1611,6 +1611,10 @@ int gv11b_init_hal(struct gk20a *g)
nvgpu_set_enabled(g, NVGPU_FECS_TRACE_FEATURE_CONTROL, true);
nvgpu_set_enabled(g, NVGPU_SUPPORT_FECS_CTXSW_TRACE, true);
#endif
#ifdef CONFIG_NVGPU_PROFILER
nvgpu_set_enabled(g, NVGPU_SUPPORT_PROFILER_V2_DEVICE, true);
nvgpu_set_enabled(g, NVGPU_SUPPORT_PROFILER_V2_CONTEXT, false);
#endif
nvgpu_set_enabled(g, NVGPU_SUPPORT_MULTIPLE_WPR, false);
#ifdef CONFIG_NVGPU_GRAPHICS

View File

@@ -1733,6 +1733,10 @@ int tu104_init_hal(struct gk20a *g)
nvgpu_set_enabled(g, NVGPU_FECS_TRACE_VA, true);
nvgpu_set_enabled(g, NVGPU_FECS_TRACE_FEATURE_CONTROL, true);
nvgpu_set_enabled(g, NVGPU_SUPPORT_FECS_CTXSW_TRACE, true);
#endif
#ifdef CONFIG_NVGPU_PROFILER
nvgpu_set_enabled(g, NVGPU_SUPPORT_PROFILER_V2_DEVICE, true);
nvgpu_set_enabled(g, NVGPU_SUPPORT_PROFILER_V2_CONTEXT, false);
#endif
nvgpu_set_enabled(g, NVGPU_SUPPORT_SEC2_RTOS, true);
nvgpu_set_enabled(g, NVGPU_SUPPORT_PMU_RTOS_FBQ, true);

View File

@@ -30,6 +30,7 @@
struct gk20a;
struct nvgpu_channel;
struct nvgpu_tsg;
struct nvgpu_profiler_object {
struct gk20a *g;
@@ -49,6 +50,13 @@ struct nvgpu_profiler_object {
*/
struct nvgpu_tsg *tsg;
/*
* If context has been bound by userspace.
* For objects with device scope, userspace should still trigger
* BIND_CONTEXT IOCTL/DEVCTL with tsg_fd = -1 for consistency.
*/
bool context_init;
/* If profiler object has reservation for each resource. */
bool reserved[NVGPU_PROFILER_PM_RESOURCE_TYPE_COUNT];
@@ -74,6 +82,10 @@ int nvgpu_profiler_alloc(struct gk20a *g,
enum nvgpu_profiler_pm_reservation_scope scope);
void nvgpu_profiler_free(struct nvgpu_profiler_object *prof);
int nvgpu_profiler_bind_context(struct nvgpu_profiler_object *prof,
struct nvgpu_tsg *tsg);
int nvgpu_profiler_unbind_context(struct nvgpu_profiler_object *prof);
int nvgpu_profiler_pm_resource_reserve(struct nvgpu_profiler_object *prof,
enum nvgpu_profiler_pm_resource_type pm_resource);
int nvgpu_profiler_pm_resource_release(struct nvgpu_profiler_object *prof,

View File

@@ -52,6 +52,7 @@ struct gk20a;
struct nvgpu_channel;
struct nvgpu_gr_ctx;
struct nvgpu_channel_hw_state;
struct nvgpu_profiler_object;
#ifdef CONFIG_NVGPU_CHANNEL_TSG_CONTROL
enum nvgpu_event_id_type;
@@ -193,6 +194,11 @@ struct nvgpu_tsg {
u32 sm_exception_mask_type;
struct nvgpu_mutex sm_exception_mask_lock;
#endif
#ifdef CONFIG_NVGPU_PROFILER
/** Pointer of profiler object to which this TSG is bound */
struct nvgpu_profiler_object *prof;
#endif
};
int nvgpu_tsg_open_common(struct gk20a *g, struct nvgpu_tsg *tsg, pid_t pid);

View File

@@ -1,7 +1,7 @@
/*
* NVGPU IOCTLs
*
* Copyright (c) 2011-2019, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2011-2020, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -26,6 +26,7 @@
#include "ioctl_as.h"
#include "ioctl_tsg.h"
#include "ioctl_dbg.h"
#include "ioctl_prof.h"
#include "module.h"
#include "os_linux.h"
#include "fecs_trace_linux.h"
@@ -91,7 +92,27 @@ static const struct file_operations gk20a_prof_ops = {
#endif
};
static const struct file_operations gk20a_tsg_ops = {
static const struct file_operations gk20a_prof_dev_ops = {
.owner = THIS_MODULE,
.release = nvgpu_prof_fops_release,
.open = nvgpu_prof_dev_fops_open,
.unlocked_ioctl = nvgpu_prof_fops_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = nvgpu_prof_fops_ioctl,
#endif
};
static const struct file_operations gk20a_prof_ctx_ops = {
.owner = THIS_MODULE,
.release = nvgpu_prof_fops_release,
.open = nvgpu_prof_ctx_fops_open,
.unlocked_ioctl = nvgpu_prof_fops_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = nvgpu_prof_fops_ioctl,
#endif
};
const struct file_operations gk20a_tsg_ops = {
.owner = THIS_MODULE,
.release = nvgpu_ioctl_tsg_dev_release,
.open = nvgpu_ioctl_tsg_dev_open,
@@ -195,6 +216,16 @@ void gk20a_user_deinit(struct device *dev, struct class *class)
cdev_del(&l->prof.cdev);
}
if (l->prof_dev.node) {
device_destroy(class, l->prof_dev.cdev.dev);
cdev_del(&l->prof_dev.cdev);
}
if (l->prof_ctx.node) {
device_destroy(class, l->prof_ctx.cdev.dev);
cdev_del(&l->prof_ctx.cdev);
}
if (l->tsg.node) {
device_destroy(class, l->tsg.cdev.dev);
cdev_del(&l->tsg.cdev);
@@ -264,6 +295,20 @@ int gk20a_user_init(struct device *dev, const char *interface_name,
if (err)
goto fail;
err = gk20a_create_device(dev, devno++, interface_name, "-prof-dev",
&l->prof_dev.cdev, &l->prof_dev.node,
&gk20a_prof_dev_ops,
class);
if (err)
goto fail;
err = gk20a_create_device(dev, devno++, interface_name, "-prof-ctx",
&l->prof_ctx.cdev, &l->prof_ctx.node,
&gk20a_prof_ctx_ops,
class);
if (err)
goto fail;
err = gk20a_create_device(dev, devno++, interface_name, "-tsg",
&l->tsg.cdev, &l->tsg.node,
&gk20a_tsg_ops,

View File

@@ -411,6 +411,7 @@ gk20a_ctrl_ioctl_gpu_characteristics(
gpu.as_ioctl_nr_last = NVGPU_AS_IOCTL_LAST;
gpu.event_ioctl_nr_last = NVGPU_EVENT_IOCTL_LAST;
gpu.ctxsw_ioctl_nr_last = NVGPU_CTXSW_IOCTL_LAST;
gpu.prof_ioctl_nr_last = NVGPU_PROFILER_IOCTL_LAST;
gpu.gpu_va_bit_count = 40;
strlcpy(gpu.chipname, g->name, sizeof(gpu.chipname));

View File

@@ -0,0 +1,229 @@
/*
* Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <uapi/linux/nvgpu.h>
#include <nvgpu/kmem.h>
#include <nvgpu/log.h>
#include <nvgpu/gk20a.h>
#include <nvgpu/nvgpu_init.h>
#include <nvgpu/profiler.h>
#include <nvgpu/pm_reservation.h>
#include <nvgpu/tsg.h>
#include "os_linux.h"
#include "ioctl_prof.h"
#include "ioctl_tsg.h"
struct nvgpu_profiler_object_priv {
struct nvgpu_profiler_object *prof;
struct gk20a *g;
};
static int nvgpu_prof_fops_open(struct gk20a *g, struct file *filp,
enum nvgpu_profiler_pm_reservation_scope scope)
{
struct nvgpu_profiler_object_priv *prof_priv;
struct nvgpu_profiler_object *prof;
int err;
nvgpu_log(g, gpu_dbg_prof, "Request to open profiler session with scope %u",
scope);
prof_priv = nvgpu_kzalloc(g, sizeof(*prof_priv));
if (prof_priv == NULL) {
return -ENOMEM;
}
err = nvgpu_profiler_alloc(g, &prof, scope);
if (err != 0) {
nvgpu_kfree(g, prof_priv);
return -ENOMEM;
}
prof_priv->g = g;
prof_priv->prof = prof;
filp->private_data = prof_priv;
nvgpu_log(g, gpu_dbg_prof,
"Profiler session with scope %u created successfully with profiler handle %u",
scope, prof->prof_handle);
return 0;
}
int nvgpu_prof_dev_fops_open(struct inode *inode, struct file *filp)
{
struct nvgpu_os_linux *l = container_of(inode->i_cdev,
struct nvgpu_os_linux, prof_dev.cdev);
struct gk20a *g;
int err;
g = nvgpu_get(&l->g);
if (!g) {
return -ENODEV;
}
if (!nvgpu_is_enabled(g, NVGPU_SUPPORT_PROFILER_V2_DEVICE)) {
nvgpu_put(g);
return -EINVAL;
}
err = nvgpu_prof_fops_open(g, filp,
NVGPU_PROFILER_PM_RESERVATION_SCOPE_DEVICE);
if (err != 0) {
nvgpu_put(g);
}
return err;
}
int nvgpu_prof_ctx_fops_open(struct inode *inode, struct file *filp)
{
struct nvgpu_os_linux *l = container_of(inode->i_cdev,
struct nvgpu_os_linux, prof_ctx.cdev);
struct gk20a *g;
int err;
g = nvgpu_get(&l->g);
if (!g) {
return -ENODEV;
}
if (!nvgpu_is_enabled(g, NVGPU_SUPPORT_PROFILER_V2_CONTEXT)) {
nvgpu_put(g);
return -EINVAL;
}
err = nvgpu_prof_fops_open(g, filp,
NVGPU_PROFILER_PM_RESERVATION_SCOPE_CONTEXT);
if (err != 0) {
nvgpu_put(g);
}
return err;
}
int nvgpu_prof_fops_release(struct inode *inode, struct file *filp)
{
struct nvgpu_profiler_object_priv *prof_priv = filp->private_data;
struct nvgpu_profiler_object *prof = prof_priv->prof;
struct gk20a *g = prof_priv->g;
nvgpu_log(g, gpu_dbg_prof,
"Request to close profiler session with scope %u and profiler handle %u",
prof->scope, prof->prof_handle);
nvgpu_profiler_free(prof);
nvgpu_kfree(g, prof_priv);
nvgpu_put(g);
nvgpu_log(g, gpu_dbg_prof, "Profiler session closed successfully");
return 0;
}
static int nvgpu_prof_ioctl_bind_context(struct nvgpu_profiler_object *prof,
struct nvgpu_profiler_bind_context_args *args)
{
int tsg_fd = args->tsg_fd;
struct nvgpu_tsg *tsg;
struct gk20a *g = prof->g;
if (prof->context_init) {
nvgpu_err(g, "Context info is already initialized");
return -EINVAL;
}
if (tsg_fd < 0) {
if (prof->scope == NVGPU_PROFILER_PM_RESERVATION_SCOPE_DEVICE) {
prof->context_init = true;
return 0;
}
return -EINVAL;
}
tsg = nvgpu_tsg_get_from_file(tsg_fd);
if (tsg == NULL) {
nvgpu_err(g, "invalid TSG fd %d", tsg_fd);
return -EINVAL;
}
return nvgpu_profiler_bind_context(prof, tsg);
}
static int nvgpu_prof_ioctl_unbind_context(struct nvgpu_profiler_object *prof)
{
return nvgpu_profiler_unbind_context(prof);
}
long nvgpu_prof_fops_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
struct nvgpu_profiler_object_priv *prof_priv = filp->private_data;
struct nvgpu_profiler_object *prof = prof_priv->prof;
struct gk20a *g = prof_priv->g;
u8 __maybe_unused buf[NVGPU_PROFILER_IOCTL_MAX_ARG_SIZE];
int err = 0;
if ((_IOC_TYPE(cmd) != NVGPU_PROFILER_IOCTL_MAGIC) ||
(_IOC_NR(cmd) == 0) ||
(_IOC_NR(cmd) > NVGPU_PROFILER_IOCTL_LAST) ||
(_IOC_SIZE(cmd) > NVGPU_PROFILER_IOCTL_MAX_ARG_SIZE)) {
return -EINVAL;
}
(void) memset(buf, 0, sizeof(buf));
if (_IOC_DIR(cmd) & _IOC_WRITE) {
if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd))) {
return -EFAULT;
}
}
nvgpu_log(g, gpu_dbg_prof, "Profiler handle %u received IOCTL cmd %u",
prof->prof_handle, cmd);
nvgpu_speculation_barrier();
switch (cmd) {
case NVGPU_PROFILER_IOCTL_BIND_CONTEXT:
err = nvgpu_prof_ioctl_bind_context(prof,
(struct nvgpu_profiler_bind_context_args *)buf);
break;
case NVGPU_PROFILER_IOCTL_UNBIND_CONTEXT:
err = nvgpu_prof_ioctl_unbind_context(prof);
break;
default:
nvgpu_err(g, "unrecognized profiler ioctl cmd: 0x%x", cmd);
err = -ENOTTY;
break;
}
if ((err == 0) && (_IOC_DIR(cmd) & _IOC_READ))
err = copy_to_user((void __user *)arg,
buf, _IOC_SIZE(cmd));
nvgpu_log(g, gpu_dbg_prof, "Profiler handle %u IOCTL err = %d",
prof->prof_handle, err);
return err;
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LINUX_IOCTL_PROF_H
#define LINUX_IOCTL_PROF_H
#include <nvgpu/types.h>
struct inode;
struct file;
int nvgpu_prof_dev_fops_open(struct inode *inode, struct file *filp);
int nvgpu_prof_ctx_fops_open(struct inode *inode, struct file *filp);
int nvgpu_prof_fops_release(struct inode *inode, struct file *filp);
long nvgpu_prof_fops_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
#endif /* LINUX_IOCTL_PROF_H */

View File

@@ -44,6 +44,29 @@ struct tsg_private {
struct nvgpu_tsg *tsg;
};
extern const struct file_operations gk20a_tsg_ops;
struct nvgpu_tsg *nvgpu_tsg_get_from_file(int fd)
{
struct nvgpu_tsg *tsg;
struct tsg_private *priv;
struct file *f = fget(fd);
if (!f) {
return NULL;
}
if (f->f_op != &gk20a_tsg_ops) {
fput(f);
return NULL;
}
priv = (struct tsg_private *)f->private_data;
tsg = priv->tsg;
fput(f);
return tsg;
}
static int nvgpu_tsg_bind_channel_fd(struct nvgpu_tsg *tsg, int ch_fd)
{
struct nvgpu_channel *ch;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -18,6 +18,8 @@ struct file;
struct gk20a;
struct nvgpu_ref;
struct nvgpu_tsg *nvgpu_tsg_get_from_file(int fd);
int nvgpu_ioctl_tsg_dev_release(struct inode *inode, struct file *filp);
int nvgpu_ioctl_tsg_dev_open(struct inode *inode, struct file *filp);
int nvgpu_ioctl_tsg_open(struct gk20a *g, struct file *filp);

View File

@@ -103,6 +103,16 @@ struct nvgpu_os_linux {
struct device *node;
} prof;
struct {
struct cdev cdev;
struct device *node;
} prof_dev;
struct {
struct cdev cdev;
struct device *node;
} prof_ctx;
struct {
struct cdev cdev;
struct device *node;

View File

@@ -315,7 +315,8 @@ struct nvgpu_gpu_characteristics {
__u32 max_css_buffer_size;
__s16 ctxsw_ioctl_nr_last;
__u8 reserved2[6];
__s16 prof_ioctl_nr_last;
__u8 reserved2[4];
__u32 max_ctxsw_ring_buffer_size;
__u32 reserved3;
@@ -1624,10 +1625,12 @@ struct nvgpu_profiler_exec_reg_ops_args {
_IOWR(NVGPU_PROFILER_IOCTL_MAGIC, 8, struct nvgpu_profiler_pma_stream_update_get_put_args)
#define NVGPU_PROFILER_IOCTL_EXEC_REG_OPS \
_IOWR(NVGPU_PROFILER_IOCTL_MAGIC, 9, struct nvgpu_profiler_exec_reg_ops_args)
#define NVGPU_PROFILER_IOCTL_UNBIND_CONTEXT \
_IO(NVGPU_PROFILER_IOCTL_MAGIC, 10)
#define NVGPU_PROFILER_IOCTL_MAX_ARG_SIZE \
sizeof(struct nvgpu_profiler_alloc_pma_stream_args)
#define NVGPU_PROFILER_IOCTL_LAST \
_IOC_NR(NVGPU_PROFILER_IOCTL_EXEC_REG_OPS)
_IOC_NR(NVGPU_PROFILER_IOCTL_UNBIND_CONTEXT)
/*