Merge pull request #3 from tomaszrybicki/add-tracing-support
Added tracing functionality
This commit is contained in:
commit
dd6b074258
@ -33,5 +33,6 @@
|
|||||||
#include "ocf_mngt.h"
|
#include "ocf_mngt.h"
|
||||||
#include "ocf_ctx.h"
|
#include "ocf_ctx.h"
|
||||||
#include "ocf_err.h"
|
#include "ocf_err.h"
|
||||||
|
#include "ocf_trace.h"
|
||||||
|
|
||||||
#endif /* __OCF_H__ */
|
#endif /* __OCF_H__ */
|
||||||
|
@ -76,7 +76,7 @@ struct ocf_io {
|
|||||||
/**
|
/**
|
||||||
* @brief OCF IO destination class
|
* @brief OCF IO destination class
|
||||||
*/
|
*/
|
||||||
uint32_t class;
|
uint32_t io_class;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief OCF IO direction
|
* @brief OCF IO direction
|
||||||
@ -157,15 +157,15 @@ void *ocf_io_get_priv(struct ocf_io *io);
|
|||||||
* @param[in] addr OCF IO destination address
|
* @param[in] addr OCF IO destination address
|
||||||
* @param[in] bytes OCF IO size in bytes
|
* @param[in] bytes OCF IO size in bytes
|
||||||
* @param[in] dir OCF IO direction
|
* @param[in] dir OCF IO direction
|
||||||
* @param[in] class OCF IO destination class
|
* @param[in] io_class OCF IO destination class
|
||||||
* @param[in] flags OCF IO flags
|
* @param[in] flags OCF IO flags
|
||||||
*/
|
*/
|
||||||
static inline void ocf_io_configure(struct ocf_io *io, uint64_t addr,
|
static inline void ocf_io_configure(struct ocf_io *io, uint64_t addr,
|
||||||
uint32_t bytes, uint32_t dir, uint32_t class, uint64_t flags)
|
uint32_t bytes, uint32_t dir, uint32_t io_class, uint64_t flags)
|
||||||
{
|
{
|
||||||
io->addr = addr;
|
io->addr = addr;
|
||||||
io->bytes = bytes;
|
io->bytes = bytes;
|
||||||
io->class = class;
|
io->io_class = io_class;
|
||||||
io->flags = flags;
|
io->flags = flags;
|
||||||
io->dir = dir;
|
io->dir = dir;
|
||||||
}
|
}
|
||||||
|
188
inc/ocf_trace.h
Normal file
188
inc/ocf_trace.h
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
* Copyright(c) 2012-2018 Intel Corporation
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __OCF_TRACE_H__
|
||||||
|
#define __OCF_TRACE_H__
|
||||||
|
|
||||||
|
#include "ocf_def.h"
|
||||||
|
#include "ocf_types.h"
|
||||||
|
|
||||||
|
typedef uint64_t log_sid_t;
|
||||||
|
|
||||||
|
#define OCF_EVENT_VERSION 1
|
||||||
|
#define OCF_TRACING_STOP 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OCF trace (event) type
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
/** IO trace description, this event is pushed first to indicate version
|
||||||
|
* of traces, number of cores and provides details about cache */
|
||||||
|
ocf_event_type_cache_desc,
|
||||||
|
|
||||||
|
/** Event describing ocf core */
|
||||||
|
ocf_event_type_core_desc,
|
||||||
|
|
||||||
|
/** IO */
|
||||||
|
ocf_event_type_io,
|
||||||
|
|
||||||
|
/** IO completion */
|
||||||
|
ocf_event_type_io_cmpl,
|
||||||
|
|
||||||
|
/** IO in file domain */
|
||||||
|
ocf_event_type_io_file,
|
||||||
|
} ocf_event_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generic OCF trace event
|
||||||
|
*/
|
||||||
|
struct ocf_event_hdr {
|
||||||
|
/** Event sequence ID */
|
||||||
|
log_sid_t sid;
|
||||||
|
|
||||||
|
/** Time stamp */
|
||||||
|
uint64_t timestamp;
|
||||||
|
|
||||||
|
/** Trace event type */
|
||||||
|
ocf_event_type type;
|
||||||
|
|
||||||
|
/** Size of this event */
|
||||||
|
uint32_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cache trace description
|
||||||
|
*/
|
||||||
|
struct ocf_event_cache_desc {
|
||||||
|
/** Event header */
|
||||||
|
struct ocf_event_hdr hdr;
|
||||||
|
|
||||||
|
/** Cache Id */
|
||||||
|
ocf_cache_id_t id;
|
||||||
|
|
||||||
|
/** Cache line size */
|
||||||
|
ocf_cache_line_size_t cache_line_size;
|
||||||
|
|
||||||
|
/** Cache mode */
|
||||||
|
ocf_cache_mode_t cache_mode;
|
||||||
|
|
||||||
|
/** Cache size in bytes*/
|
||||||
|
uint64_t cache_size;
|
||||||
|
|
||||||
|
/** Number of cores */
|
||||||
|
uint32_t cores_no;
|
||||||
|
|
||||||
|
/** Number of IO queues */
|
||||||
|
uint32_t io_queues_no;
|
||||||
|
|
||||||
|
/** Trace version */
|
||||||
|
uint32_t version;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Core trace description
|
||||||
|
*/
|
||||||
|
struct ocf_event_core_desc {
|
||||||
|
/** Event header */
|
||||||
|
struct ocf_event_hdr hdr;
|
||||||
|
|
||||||
|
/** Core Id */
|
||||||
|
ocf_core_id_t id;
|
||||||
|
|
||||||
|
/** Core size in bytes */
|
||||||
|
uint64_t core_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief IO operation */
|
||||||
|
typedef enum {
|
||||||
|
/** Read */
|
||||||
|
ocf_event_operation_rd = 'R',
|
||||||
|
|
||||||
|
/** Write */
|
||||||
|
ocf_event_operation_wr = 'W',
|
||||||
|
|
||||||
|
/** Flush */
|
||||||
|
ocf_event_operation_flush = 'F',
|
||||||
|
|
||||||
|
/** Discard */
|
||||||
|
ocf_event_operation_discard = 'D',
|
||||||
|
} ocf_event_operation_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IO trace event
|
||||||
|
*/
|
||||||
|
struct ocf_event_io {
|
||||||
|
/** Trace event header */
|
||||||
|
struct ocf_event_hdr hdr;
|
||||||
|
|
||||||
|
/** Address of IO in bytes */
|
||||||
|
uint64_t addr;
|
||||||
|
|
||||||
|
/** Size of IO in bytes */
|
||||||
|
uint32_t len;
|
||||||
|
|
||||||
|
/** IO class of IO */
|
||||||
|
uint32_t io_class;
|
||||||
|
|
||||||
|
/** Core ID */
|
||||||
|
ocf_core_id_t core_id;
|
||||||
|
|
||||||
|
/** Operation type: read, write, trim or flush **/
|
||||||
|
ocf_event_operation_t operation;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IO completion event
|
||||||
|
*/
|
||||||
|
struct ocf_event_io_cmpl {
|
||||||
|
/** Trace event header */
|
||||||
|
struct ocf_event_hdr hdr;
|
||||||
|
|
||||||
|
/** Reference event sequence ID */
|
||||||
|
log_sid_t rsid;
|
||||||
|
|
||||||
|
/** Was IO a cache hit or miss */
|
||||||
|
bool is_hit;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Push log callback.
|
||||||
|
*
|
||||||
|
* @param[in] cache OCF cache
|
||||||
|
* @param[in] trace_ctx Tracing context
|
||||||
|
* @param[in] qid Queue Id
|
||||||
|
* @param[out] trace Event log
|
||||||
|
* @param[out] size Size of event log
|
||||||
|
*
|
||||||
|
* @return 0 If pushing trace succeeded
|
||||||
|
* @return Non-zero error
|
||||||
|
*/
|
||||||
|
typedef void (*ocf_trace_callback_t)(ocf_cache_t cache, void *trace_ctx,
|
||||||
|
uint32_t qid, const void* trace, const uint32_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start tracing
|
||||||
|
*
|
||||||
|
* @param[in] cache OCF cache
|
||||||
|
* @param[in] trace_ctx Tracing context
|
||||||
|
* @param[in] trace_callback Callback used for pushing logs
|
||||||
|
*
|
||||||
|
* @retval 0 Tracing started successfully
|
||||||
|
* @retval Non-zero Error
|
||||||
|
*/
|
||||||
|
int ocf_mgnt_start_trace(ocf_cache_t cache, void *trace_ctx,
|
||||||
|
ocf_trace_callback_t trace_callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stop tracing
|
||||||
|
*
|
||||||
|
* @param[in] cache OCF cache
|
||||||
|
*
|
||||||
|
* @retval 0 Tracing stopped successfully
|
||||||
|
* @retval Non-zero Error
|
||||||
|
*/
|
||||||
|
int ocf_mgnt_stop_trace(ocf_cache_t cache);
|
||||||
|
|
||||||
|
#endif /* __OCF_TRACE_H__ */
|
@ -222,7 +222,7 @@ ocf_cache_mode_t ocf_get_effective_cache_mode(ocf_cache_t cache,
|
|||||||
return ocf_cache_mode_pt;
|
return ocf_cache_mode_pt;
|
||||||
|
|
||||||
mode = ocf_part_get_cache_mode(cache,
|
mode = ocf_part_get_cache_mode(cache,
|
||||||
ocf_part_class2id(cache, io->class));
|
ocf_part_class2id(cache, io->io_class));
|
||||||
if (!ocf_cache_mode_is_valid(mode))
|
if (!ocf_cache_mode_is_valid(mode))
|
||||||
mode = cache->conf_meta->cache_mode;
|
mode = cache->conf_meta->cache_mode;
|
||||||
|
|
||||||
|
@ -17,10 +17,24 @@
|
|||||||
#include "ocf_stats_priv.h"
|
#include "ocf_stats_priv.h"
|
||||||
#include "cleaning/cleaning.h"
|
#include "cleaning/cleaning.h"
|
||||||
#include "ocf_logger_priv.h"
|
#include "ocf_logger_priv.h"
|
||||||
|
#include "ocf/ocf_trace.h"
|
||||||
|
|
||||||
#define DIRTY_FLUSHED 1
|
#define DIRTY_FLUSHED 1
|
||||||
#define DIRTY_NOT_FLUSHED 0
|
#define DIRTY_NOT_FLUSHED 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Structure used for aggregating trace-related ocf_cache fields
|
||||||
|
*/
|
||||||
|
struct ocf_trace {
|
||||||
|
/* Placeholder for push_event callback */
|
||||||
|
volatile ocf_trace_callback_t trace_callback;
|
||||||
|
|
||||||
|
/* Telemetry context */
|
||||||
|
volatile void *trace_ctx;
|
||||||
|
|
||||||
|
env_atomic64 trace_seq_ref;
|
||||||
|
};
|
||||||
|
|
||||||
struct ocf_metadata_uuid {
|
struct ocf_metadata_uuid {
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
uint8_t data[OCF_DATA_OBJ_UUID_MAX_SIZE];
|
uint8_t data[OCF_DATA_OBJ_UUID_MAX_SIZE];
|
||||||
@ -208,6 +222,8 @@ struct ocf_cache {
|
|||||||
bool use_submit_io_fast;
|
bool use_submit_io_fast;
|
||||||
|
|
||||||
void *cleaning_policy_context;
|
void *cleaning_policy_context;
|
||||||
|
|
||||||
|
struct ocf_trace trace;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ocf_cache_log_prefix(cache, lvl, prefix, fmt, ...) \
|
#define ocf_cache_log_prefix(cache, lvl, prefix, fmt, ...) \
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "utils/utils_part.h"
|
#include "utils/utils_part.h"
|
||||||
#include "utils/utils_device.h"
|
#include "utils/utils_device.h"
|
||||||
#include "ocf_request.h"
|
#include "ocf_request.h"
|
||||||
|
#include "ocf_trace_priv.h"
|
||||||
|
|
||||||
struct ocf_core_dobj {
|
struct ocf_core_dobj {
|
||||||
ocf_core_t core;
|
ocf_core_t core;
|
||||||
@ -287,7 +288,7 @@ static inline int ocf_core_validate_io(struct ocf_io *io)
|
|||||||
if (io->addr + io->bytes > ocf_dobj_get_length(io->obj))
|
if (io->addr + io->bytes > ocf_dobj_get_length(io->obj))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (io->class >= OCF_IO_CLASS_MAX)
|
if (io->io_class >= OCF_IO_CLASS_MAX)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (io->dir != OCF_READ && io->dir != OCF_WRITE)
|
if (io->dir != OCF_READ && io->dir != OCF_WRITE)
|
||||||
@ -304,6 +305,9 @@ static inline int ocf_core_validate_io(struct ocf_io *io)
|
|||||||
|
|
||||||
static void ocf_req_complete(struct ocf_request *req, int error)
|
static void ocf_req_complete(struct ocf_request *req, int error)
|
||||||
{
|
{
|
||||||
|
/* Log trace */
|
||||||
|
ocf_trace_io_cmpl(ocf_io_to_core_io(req->io), req->cache);
|
||||||
|
|
||||||
/* Complete IO */
|
/* Complete IO */
|
||||||
ocf_io_end(req->io, error);
|
ocf_io_end(req->io, error);
|
||||||
|
|
||||||
@ -335,6 +339,8 @@ void ocf_core_submit_io_mode(struct ocf_io *io, ocf_cache_mode_t cache_mode)
|
|||||||
core = ocf_data_obj_to_core(io->obj);
|
core = ocf_data_obj_to_core(io->obj);
|
||||||
cache = ocf_core_get_cache(core);
|
cache = ocf_core_get_cache(core);
|
||||||
|
|
||||||
|
ocf_trace_init_io(core_io, cache);
|
||||||
|
|
||||||
if (unlikely(!env_bit_test(ocf_cache_state_running,
|
if (unlikely(!env_bit_test(ocf_cache_state_running,
|
||||||
&cache->cache_state))) {
|
&cache->cache_state))) {
|
||||||
ocf_io_end(io, -EIO);
|
ocf_io_end(io, -EIO);
|
||||||
@ -358,9 +364,6 @@ void ocf_core_submit_io_mode(struct ocf_io *io, ocf_cache_mode_t cache_mode)
|
|||||||
dec_counter_if_req_was_dirty(core_io, cache);
|
dec_counter_if_req_was_dirty(core_io, cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cache->conf_meta->valid_parts_no <= 1)
|
|
||||||
io->class = 0;
|
|
||||||
|
|
||||||
core_io->req = ocf_req_new(cache, ocf_core_get_id(core),
|
core_io->req = ocf_req_new(cache, ocf_core_get_id(core),
|
||||||
io->addr, io->bytes, io->dir);
|
io->addr, io->bytes, io->dir);
|
||||||
if (!core_io->req) {
|
if (!core_io->req) {
|
||||||
@ -373,7 +376,7 @@ void ocf_core_submit_io_mode(struct ocf_io *io, ocf_cache_mode_t cache_mode)
|
|||||||
req_cache_mode = ocf_req_cache_mode_d2c;
|
req_cache_mode = ocf_req_cache_mode_d2c;
|
||||||
|
|
||||||
core_io->req->io_queue = io->io_queue;
|
core_io->req->io_queue = io->io_queue;
|
||||||
core_io->req->part_id = ocf_part_class2id(cache, io->class);
|
core_io->req->part_id = ocf_part_class2id(cache, io->io_class);
|
||||||
core_io->req->data = core_io->data;
|
core_io->req->data = core_io->data;
|
||||||
core_io->req->complete = ocf_req_complete;
|
core_io->req->complete = ocf_req_complete;
|
||||||
core_io->req->io = io;
|
core_io->req->io = io;
|
||||||
@ -382,6 +385,11 @@ void ocf_core_submit_io_mode(struct ocf_io *io, ocf_cache_mode_t cache_mode)
|
|||||||
|
|
||||||
ocf_core_update_stats(core, io);
|
ocf_core_update_stats(core, io);
|
||||||
|
|
||||||
|
if (io->dir == OCF_WRITE)
|
||||||
|
ocf_trace_io(core_io, ocf_event_operation_wr, cache);
|
||||||
|
else if (io->dir == OCF_READ)
|
||||||
|
ocf_trace_io(core_io, ocf_event_operation_rd, cache);
|
||||||
|
|
||||||
ocf_io_get(io);
|
ocf_io_get(io);
|
||||||
ret = ocf_engine_hndl_req(core_io->req, req_cache_mode);
|
ret = ocf_engine_hndl_req(core_io->req, req_cache_mode);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@ -395,6 +403,7 @@ int ocf_core_submit_io_fast(struct ocf_io *io)
|
|||||||
{
|
{
|
||||||
struct ocf_core_io *core_io;
|
struct ocf_core_io *core_io;
|
||||||
ocf_req_cache_mode_t req_cache_mode;
|
ocf_req_cache_mode_t req_cache_mode;
|
||||||
|
struct ocf_event_io trace_event;
|
||||||
struct ocf_request *req;
|
struct ocf_request *req;
|
||||||
ocf_core_t core;
|
ocf_core_t core;
|
||||||
ocf_cache_t cache;
|
ocf_cache_t cache;
|
||||||
@ -444,9 +453,6 @@ int ocf_core_submit_io_fast(struct ocf_io *io)
|
|||||||
req_cache_mode = ocf_req_cache_mode_fast;
|
req_cache_mode = ocf_req_cache_mode_fast;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cache->conf_meta->valid_parts_no <= 1)
|
|
||||||
io->class = 0;
|
|
||||||
|
|
||||||
core_io->req = ocf_req_new_extended(cache, ocf_core_get_id(core),
|
core_io->req = ocf_req_new_extended(cache, ocf_core_get_id(core),
|
||||||
io->addr, io->bytes, io->dir);
|
io->addr, io->bytes, io->dir);
|
||||||
// We need additional pointer to req in case completion arrives before
|
// We need additional pointer to req in case completion arrives before
|
||||||
@ -465,16 +471,26 @@ int ocf_core_submit_io_fast(struct ocf_io *io)
|
|||||||
}
|
}
|
||||||
|
|
||||||
req->io_queue = io->io_queue;
|
req->io_queue = io->io_queue;
|
||||||
req->part_id = ocf_part_class2id(cache, io->class);
|
req->part_id = ocf_part_class2id(cache, io->io_class);
|
||||||
req->data = core_io->data;
|
req->data = core_io->data;
|
||||||
req->complete = ocf_req_complete;
|
req->complete = ocf_req_complete;
|
||||||
req->io = io;
|
req->io = io;
|
||||||
|
|
||||||
ocf_core_update_stats(core, io);
|
ocf_core_update_stats(core, io);
|
||||||
|
|
||||||
|
if (cache->trace.trace_callback) {
|
||||||
|
if (io->dir == OCF_WRITE)
|
||||||
|
ocf_trace_prep_io_event(&trace_event, core_io, ocf_event_operation_wr);
|
||||||
|
else if (io->dir == OCF_READ)
|
||||||
|
ocf_trace_prep_io_event(&trace_event, core_io, ocf_event_operation_rd);
|
||||||
|
}
|
||||||
|
|
||||||
ocf_io_get(io);
|
ocf_io_get(io);
|
||||||
|
|
||||||
fast = ocf_engine_hndl_fast_req(req, req_cache_mode);
|
fast = ocf_engine_hndl_fast_req(req, req_cache_mode);
|
||||||
if (fast != OCF_FAST_PATH_NO) {
|
if (fast != OCF_FAST_PATH_NO) {
|
||||||
|
ocf_trace_push(cache, core_io->req->io_queue,
|
||||||
|
&trace_event, sizeof(trace_event));
|
||||||
ocf_seq_cutoff_update(core, req);
|
ocf_seq_cutoff_update(core, req);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -529,6 +545,7 @@ static void ocf_core_data_obj_submit_flush(struct ocf_io *io)
|
|||||||
core_io->req->io = io;
|
core_io->req->io = io;
|
||||||
core_io->req->data = core_io->data;
|
core_io->req->data = core_io->data;
|
||||||
|
|
||||||
|
ocf_trace_io(core_io, ocf_event_operation_flush, cache);
|
||||||
ocf_io_get(io);
|
ocf_io_get(io);
|
||||||
ocf_engine_hndl_ops_req(core_io->req);
|
ocf_engine_hndl_ops_req(core_io->req);
|
||||||
}
|
}
|
||||||
@ -571,6 +588,7 @@ static void ocf_core_data_obj_submit_discard(struct ocf_io *io)
|
|||||||
core_io->req->io = io;
|
core_io->req->io = io;
|
||||||
core_io->req->data = core_io->data;
|
core_io->req->data = core_io->data;
|
||||||
|
|
||||||
|
ocf_trace_io(core_io, ocf_event_operation_discard, cache);
|
||||||
ocf_io_get(io);
|
ocf_io_get(io);
|
||||||
ocf_engine_hndl_discard_req(core_io->req);
|
ocf_engine_hndl_discard_req(core_io->req);
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,12 @@ struct ocf_core_io {
|
|||||||
|
|
||||||
struct ocf_request *req;
|
struct ocf_request *req;
|
||||||
ctx_data_t *data;
|
ctx_data_t *data;
|
||||||
|
|
||||||
|
log_sid_t sid;
|
||||||
|
/*!< Sequence ID */
|
||||||
|
|
||||||
|
uint64_t timestamp;
|
||||||
|
/*!< Timestamp */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ocf_core {
|
struct ocf_core {
|
||||||
|
@ -17,6 +17,12 @@ struct ocf_queue {
|
|||||||
struct list_head io_list;
|
struct list_head io_list;
|
||||||
env_spinlock io_list_lock;
|
env_spinlock io_list_lock;
|
||||||
|
|
||||||
|
/* Tracing reference counter */
|
||||||
|
env_atomic64 trace_ref_cntr;
|
||||||
|
|
||||||
|
/* Tracing stop request */
|
||||||
|
env_atomic trace_stop;
|
||||||
|
|
||||||
void *priv;
|
void *priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
156
src/ocf_trace.c
Normal file
156
src/ocf_trace.c
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* Copyright(c) 2012-2018 Intel Corporation
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ocf_env.h"
|
||||||
|
#include "ocf_priv.h"
|
||||||
|
#include "ocf/ocf.h"
|
||||||
|
#include "ocf/ocf_trace.h"
|
||||||
|
#include "ocf_core_priv.h"
|
||||||
|
#include "ocf_cache_priv.h"
|
||||||
|
#include "ocf_trace_priv.h"
|
||||||
|
|
||||||
|
struct core_trace_visitor_ctx {
|
||||||
|
ocf_cache_t cache;
|
||||||
|
uint32_t io_queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int _ocf_core_desc(ocf_core_t core, void *ctx)
|
||||||
|
{
|
||||||
|
struct ocf_event_core_desc core_desc;
|
||||||
|
struct core_trace_visitor_ctx *visitor_ctx =
|
||||||
|
(struct core_trace_visitor_ctx *) ctx;
|
||||||
|
ocf_cache_t cache = visitor_ctx->cache;
|
||||||
|
|
||||||
|
ocf_event_init_hdr(&core_desc.hdr, ocf_event_type_core_desc,
|
||||||
|
ocf_trace_seq_id(cache), env_get_tick_ns(), sizeof(core_desc));
|
||||||
|
core_desc.id = ocf_core_get_id(core);
|
||||||
|
core_desc.core_size = ocf_dobj_get_length(
|
||||||
|
ocf_core_get_data_object(core));
|
||||||
|
|
||||||
|
ocf_trace_push(cache, visitor_ctx->io_queue,
|
||||||
|
&core_desc, sizeof(core_desc));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _ocf_trace_cache_info(ocf_cache_t cache, uint32_t io_queue)
|
||||||
|
{
|
||||||
|
struct ocf_event_cache_desc cache_desc;
|
||||||
|
int retval;
|
||||||
|
struct core_trace_visitor_ctx visitor_ctx;
|
||||||
|
|
||||||
|
ocf_event_init_hdr(&cache_desc.hdr, ocf_event_type_cache_desc,
|
||||||
|
ocf_trace_seq_id(cache), env_get_tick_ns(), sizeof(cache_desc));
|
||||||
|
|
||||||
|
cache_desc.id = ocf_cache_get_id(cache);
|
||||||
|
cache_desc.cache_line_size = ocf_cache_get_line_size(cache);
|
||||||
|
cache_desc.cache_mode = ocf_cache_get_mode(cache);
|
||||||
|
|
||||||
|
if (ocf_cache_is_device_attached(cache)) {
|
||||||
|
/* Attached cache */
|
||||||
|
cache_desc.cache_size = ocf_dobj_get_length(
|
||||||
|
ocf_cache_get_data_object(cache));
|
||||||
|
} else {
|
||||||
|
cache_desc.cache_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache_desc.cores_no = ocf_cache_get_core_count(cache);
|
||||||
|
cache_desc.version = OCF_EVENT_VERSION;
|
||||||
|
cache_desc.io_queues_no = cache->io_queues_no;
|
||||||
|
|
||||||
|
ocf_trace_push(cache, io_queue, &cache_desc, sizeof(cache_desc));
|
||||||
|
|
||||||
|
visitor_ctx.cache = cache;
|
||||||
|
visitor_ctx.io_queue = io_queue;
|
||||||
|
|
||||||
|
retval = ocf_core_visit(cache, _ocf_core_desc, &visitor_ctx, true);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ocf_mgnt_start_trace(ocf_cache_t cache, void *trace_ctx,
|
||||||
|
ocf_trace_callback_t trace_callback)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
OCF_CHECK_NULL(cache);
|
||||||
|
|
||||||
|
if (!trace_callback) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = ocf_mngt_cache_lock(cache);
|
||||||
|
if (result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if (cache->trace.trace_callback) {
|
||||||
|
ocf_cache_log(cache, log_err,
|
||||||
|
"Tracing already started for cache %u\n",
|
||||||
|
ocf_cache_get_id(cache));
|
||||||
|
ocf_mngt_cache_unlock(cache);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache->trace.trace_callback = trace_callback;
|
||||||
|
cache->trace.trace_ctx = trace_ctx;
|
||||||
|
|
||||||
|
// Reset trace stop flag
|
||||||
|
for (int queue = 0; queue < cache->io_queues_no; queue++) {
|
||||||
|
env_atomic_set(&cache->io_queues[queue].trace_stop, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < cache->io_queues_no; i++) {
|
||||||
|
result = _ocf_trace_cache_info(cache, i);
|
||||||
|
if (result)
|
||||||
|
goto trace_deinit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ocf_cache_log(cache, log_info,
|
||||||
|
"Tracing started for cache %u\n", ocf_cache_get_id(cache));
|
||||||
|
|
||||||
|
ocf_mngt_cache_unlock(cache);
|
||||||
|
return result;
|
||||||
|
|
||||||
|
trace_deinit:
|
||||||
|
cache->trace.trace_callback = NULL;
|
||||||
|
ocf_mngt_cache_unlock(cache);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ocf_mgnt_stop_trace(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
result = ocf_mngt_cache_lock(cache);
|
||||||
|
if (result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if (!cache->trace.trace_callback) {
|
||||||
|
ocf_cache_log(cache, log_err,
|
||||||
|
"Tracing not started for cache %u\n",
|
||||||
|
ocf_cache_get_id(cache));
|
||||||
|
ocf_mngt_cache_unlock(cache);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set trace stop flag
|
||||||
|
for (int queue = 0; queue < cache->io_queues_no; queue++) {
|
||||||
|
env_atomic_set(&cache->io_queues[queue].trace_stop, OCF_TRACING_STOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
cache->trace.trace_callback = NULL;
|
||||||
|
cache->trace.trace_ctx = NULL;
|
||||||
|
|
||||||
|
// Poll for all ongoing traces completion
|
||||||
|
while (ocf_is_trace_ongoing(cache)) {
|
||||||
|
env_msleep(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
ocf_mngt_cache_unlock(cache);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
130
src/ocf_trace_priv.h
Normal file
130
src/ocf_trace_priv.h
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright(c) 2012-2018 Intel Corporation
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __OCF_TRACE_PRIV_H__
|
||||||
|
#define __OCF_TRACE_PRIV_H__
|
||||||
|
|
||||||
|
#include "ocf/ocf_trace.h"
|
||||||
|
#include "engine/engine_common.h"
|
||||||
|
#include "ocf_request.h"
|
||||||
|
#include "ocf_core_priv.h"
|
||||||
|
#include "ocf_queue_priv.h"
|
||||||
|
|
||||||
|
static inline bool ocf_is_trace_ongoing(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < cache->io_queues_no; i++) {
|
||||||
|
if (env_atomic64_read(&cache->io_queues[i].trace_ref_cntr)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static inline void ocf_event_init_hdr(struct ocf_event_hdr *hdr,
|
||||||
|
ocf_event_type type, uint64_t sid, uint64_t timestamp,
|
||||||
|
uint32_t size)
|
||||||
|
{
|
||||||
|
hdr->sid = sid;
|
||||||
|
hdr->timestamp = timestamp;
|
||||||
|
hdr->type = type;
|
||||||
|
hdr->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t ocf_trace_seq_id(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
return env_atomic64_inc_return(&cache->trace.trace_seq_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ocf_trace_init_io(struct ocf_core_io *io, ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
io->timestamp = env_get_tick_ns();
|
||||||
|
io->sid = ocf_trace_seq_id(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ocf_trace_prep_io_event(struct ocf_event_io *ev,
|
||||||
|
struct ocf_core_io *io, ocf_event_operation_t op)
|
||||||
|
{
|
||||||
|
struct ocf_request *rq = io->req;
|
||||||
|
|
||||||
|
ocf_event_init_hdr(&ev->hdr, ocf_event_type_io, io->sid,
|
||||||
|
io->timestamp, sizeof(*ev));
|
||||||
|
|
||||||
|
ev->addr = rq->byte_position;
|
||||||
|
if (op == ocf_event_operation_discard)
|
||||||
|
ev->len = rq->discard.nr_sects << ENV_SECTOR_SHIFT;
|
||||||
|
else
|
||||||
|
ev->len = rq->byte_length;
|
||||||
|
|
||||||
|
ev->operation = op;
|
||||||
|
ev->core_id = rq->core_id;
|
||||||
|
|
||||||
|
ev->io_class = rq->io->io_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ocf_trace_push(ocf_cache_t cache, uint32_t io_queue,
|
||||||
|
void *trace, uint32_t size)
|
||||||
|
{
|
||||||
|
ocf_trace_callback_t trace_callback;
|
||||||
|
void *trace_ctx;
|
||||||
|
|
||||||
|
if (cache->trace.trace_callback == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
env_atomic64_inc(&cache->io_queues[io_queue].trace_ref_cntr);
|
||||||
|
|
||||||
|
if (env_atomic_read(&cache->io_queues[io_queue].trace_stop)) {
|
||||||
|
// Tracing stop was requested
|
||||||
|
env_atomic64_dec(&cache->io_queues[io_queue].trace_ref_cntr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remember callback and context pointers.
|
||||||
|
* These will be valid even when later on original pointers
|
||||||
|
* will be set to NULL as cleanup will wait till trace
|
||||||
|
* reference counter is zero
|
||||||
|
*/
|
||||||
|
trace_callback = cache->trace.trace_callback;
|
||||||
|
trace_ctx = cache->trace.trace_ctx;
|
||||||
|
|
||||||
|
if (trace_callback && trace_ctx) {
|
||||||
|
trace_callback(cache, trace_ctx, io_queue, trace, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
env_atomic64_dec(&cache->io_queues[io_queue].trace_ref_cntr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ocf_trace_io(struct ocf_core_io *io, ocf_event_operation_t dir, ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
struct ocf_event_io ev;
|
||||||
|
struct ocf_request *rq;
|
||||||
|
|
||||||
|
if (!cache->trace.trace_callback)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rq = io->req;
|
||||||
|
ocf_trace_prep_io_event(&ev, io, dir);
|
||||||
|
|
||||||
|
ocf_trace_push(cache, rq->io_queue, &ev, sizeof(ev));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ocf_trace_io_cmpl(struct ocf_core_io *io, ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
struct ocf_event_io_cmpl ev;
|
||||||
|
struct ocf_request *rq;
|
||||||
|
|
||||||
|
if (!cache->trace.trace_callback)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rq = io->req;
|
||||||
|
ocf_event_init_hdr(&ev.hdr, ocf_event_type_io_cmpl,
|
||||||
|
ocf_trace_seq_id(cache), env_get_tick_ns(), sizeof(ev));
|
||||||
|
ev.rsid = io->sid;
|
||||||
|
ev.is_hit = ocf_engine_is_hit(rq);
|
||||||
|
|
||||||
|
ocf_trace_push(cache, rq->io_queue, &ev, sizeof(ev));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __OCF_TRACE_PRIV_H__ */
|
@ -217,7 +217,7 @@ void ocf_submit_cache_reqs(struct ocf_cache *cache,
|
|||||||
{
|
{
|
||||||
struct ocf_counters_block *cache_stats;
|
struct ocf_counters_block *cache_stats;
|
||||||
uint64_t flags = req->io ? req->io->flags : 0;
|
uint64_t flags = req->io ? req->io->flags : 0;
|
||||||
uint32_t class = req->io ? req->io->class : 0;
|
uint32_t class = req->io ? req->io->io_class : 0;
|
||||||
uint64_t addr, bytes, total_bytes = 0;
|
uint64_t addr, bytes, total_bytes = 0;
|
||||||
struct ocf_io *io;
|
struct ocf_io *io;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
@ -317,7 +317,7 @@ void ocf_submit_obj_req(ocf_data_obj_t obj, struct ocf_request *req,
|
|||||||
struct ocf_cache *cache = req->cache;
|
struct ocf_cache *cache = req->cache;
|
||||||
struct ocf_counters_block *core_stats;
|
struct ocf_counters_block *core_stats;
|
||||||
uint64_t flags = req->io ? req->io->flags : 0;
|
uint64_t flags = req->io ? req->io->flags : 0;
|
||||||
uint32_t class = req->io ? req->io->class : 0;
|
uint32_t class = req->io ? req->io->io_class : 0;
|
||||||
int dir = req->rw;
|
int dir = req->rw;
|
||||||
struct ocf_io *io;
|
struct ocf_io *io;
|
||||||
int err;
|
int err;
|
||||||
|
Loading…
Reference in New Issue
Block a user