* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/err.h>
#include <stdlib.h>
+#include "../cs-etm.h"
#include "cs-etm-decoder.h"
#include "../util.h"
+#include "../util/intlist.h"
#include "c_api/opencsd_c_api.h"
#include "ocsd_if_types.h"
static int cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
const ocsd_generic_trace_elem *elem,
+ const uint8_t trace_chan_id,
enum cs_etm_sample_type sample_type)
{
int err = 0;
uint32_t et = 0;
+ struct int_node *inode = NULL;
if (decoder == NULL) return -1;
if (err) return err;
et = decoder->end_tail;
+ /* Search the RB tree for the cpu associated with this traceID */
+ inode = intlist__find(traceid_list, trace_chan_id);
+ if (!inode)
+ return PTR_ERR(inode);
decoder->packet_buffer[et].sample_type = sample_type;
decoder->packet_buffer[et].start_addr = elem->st_addr;
decoder->packet_buffer[et].end_addr = elem->en_addr;
decoder->packet_buffer[et].exc = false;
decoder->packet_buffer[et].exc_ret = false;
+ decoder->packet_buffer[et].cpu = *((int*)inode->priv);
+
et = (et + 1) & (MAX_BUFFER - 1);
decoder->end_tail = et;
//decoder->discontinuity = true;
//break;
case OCSD_GEN_TRC_ELEM_INSTR_RANGE:
- cs_etm_decoder__buffer_packet(decoder,elem, CS_ETM_RANGE);
+ cs_etm_decoder__buffer_packet(decoder,elem,
+ trace_chan_id, CS_ETM_RANGE);
resp = OCSD_RESP_WAIT;
break;
case OCSD_GEN_TRC_ELEM_EXCEPTION:
decoder->packet_buffer[i].end_addr = 0xdeadbeefdeadbeefUL;
decoder->packet_buffer[i].exc = false;
decoder->packet_buffer[i].exc_ret = false;
+ decoder->packet_buffer[i].cpu = INT_MIN;
}
}
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/bitops.h>
#include "evlist.h"
#include "machine.h"
#include "util.h"
+#include "util/intlist.h"
#include "color.h"
#include "cs-etm.h"
#include "cs-etm-decoder/cs-etm-decoder.h"
{
size_t i;
+ struct int_node *inode, *tmp;
struct cs_etm_auxtrace *aux = container_of(session->auxtrace,
struct cs_etm_auxtrace,
auxtrace);
auxtrace_heap__free(&aux->heap);
cs_etm__free_events(session);
session->auxtrace = NULL;
+
+ /* First remove all traceID/CPU# nodes from the RB tree */
+ intlist__for_each_safe(inode, tmp, traceid_list)
+ intlist__remove(traceid_list, inode);
+ /* Then the RB tree itself */
+ intlist__delete(traceid_list);
+
//thread__delete(aux->unknown_thread);
for (i = 0; i < aux->num_cpu; ++i) {
zfree(&aux->metadata[i]);
sample.id = etmq->etm->instructions_id;
sample.stream_id = etmq->etm->instructions_id;
sample.period = (end_addr - start_addr) >> 2;
- sample.cpu = etmq->cpu;
+ sample.cpu = packet->cpu;
sample.flags = 0; // etmq->flags;
sample.insn_len = 1; // etmq->insn_len;
size_t priv_size = 0;
size_t num_cpu;
struct cs_etm_auxtrace *etm = 0;
- int err = 0;
+ int err = 0, idx = -1;
u64 *ptr;
u64 *hdr = NULL;
u64 **metadata = NULL;
size_t i,j,k;
unsigned pmu_type;
+ struct int_node *inode;
+
+ /*
+ * sizeof(auxtrace_info_event::type) +
+ * sizeof(auxtrace_info_event::reserved) == 8
+ */
+ info_header_size = 8;
if (total_size < (event_header_size + info_header_size))
return -EINVAL;
return -EINVAL;
}
+ /*
+ * Create an RB tree for traceID-CPU# tuple. Since the conversion has
+ * to be made for each packet that gets decoded optimizing access in
+ * anything other than a sequential array is worth doing.
+ */
+ traceid_list = intlist__new(NULL);
+ if (!traceid_list)
+ return -ENOMEM;
+
metadata = zalloc(sizeof(u64 *) * num_cpu);
+ if (!metadata) {
+ err = -ENOMEM;
+ goto err_free_traceid_list;
+ }
if (metadata == NULL) {
return -EINVAL;
for (k = 0; k < CS_ETM_PRIV_MAX; k++) {
metadata[j][k] = ptr[i+k];
}
+
+ /* The traceID is our handle */
+ idx = metadata[j][CS_ETM_ETMIDR];
i += CS_ETM_PRIV_MAX;
} else if (ptr[i] == __perf_cs_etmv4_magic) {
metadata[j] = zalloc(sizeof(u64)*CS_ETMV4_PRIV_MAX);
for (k = 0; k < CS_ETMV4_PRIV_MAX; k++) {
metadata[j][k] = ptr[i+k];
}
+
+ /* The traceID is our handle */
+ idx = metadata[j][CS_ETMV4_TRCTRACEIDR];
i += CS_ETMV4_PRIV_MAX;
}
+
+ /* Get an RB node for this CPU */
+ inode = intlist__findnew(traceid_list, idx);
+
+ /* Something went wrong, no need to continue */
+ if (!inode) {
+ err = PTR_ERR(inode);
+ goto err_free_metadata;
+ }
+
+ /*
+ * The node for that CPU should not have been taken already.
+ * Backout if that's the case.
+ */
+ if (inode->priv) {
+ err = -EINVAL;
+ goto err_free_metadata;
+ }
+
+ /* All good, associate the traceID with the CPU# */
+ inode->priv = &metadata[j][CS_ETM_CPU];
+
}
if (i*8 != priv_size)
session->auxtrace = NULL;
err_free:
free(etm);
+err_free_metadata:
+ /* No need to check @metadata[j], free(NULL) is supported */
+ for (j = 0; j < num_cpu; ++j)
+ free(metadata[j]);
+ free(metadata);
+err_free_traceid_list:
+ intlist__delete(traceid_list);
+
return err;
}