Menggunakan streaming dengan TraceProcessor

Secara default, TraceProcessor mengakses data dengan memuatnya ke dalam memori saat jejak diproses. Pendekatan buffering ini mudah digunakan, tetapi bisa mahal dalam hal penggunaan memori.

TraceProcessor juga menyediakan trace.UseStreaming(), yang mendukung akses beberapa jenis data pelacakan secara streaming (memproses data saat dibaca dari file pelacakan, daripada menyimpan data tersebut dalam memori). Misalnya, sebuah "trace" syscalls bisa sangat besar, dan buffering seluruh daftar syscalls dalam sebuah "trace" bisa sangat mahal.

Mengakses data yang di-buffer

Kode berikut menunjukkan cara mengakses data syscall dengan cara yang normal dan ter-buffer melalui trace.UseSyscalls():

using Microsoft.Windows.EventTracing;
using Microsoft.Windows.EventTracing.Processes;
using Microsoft.Windows.EventTracing.Syscalls;
using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        if (args.Length != 1)
        {
            Console.Error.WriteLine("Usage: <trace.etl>");
            return;
        }

        using (ITraceProcessor trace = TraceProcessor.Create(args[0]))
        {
            IPendingResult<ISyscallDataSource> pendingSyscallData = trace.UseSyscalls();

            trace.Process();

            ISyscallDataSource syscallData = pendingSyscallData.Result;

            Dictionary<IProcess, int> syscallsPerCommandLine = new Dictionary<IProcess, int>();

            foreach (ISyscall syscall in syscallData.Syscalls)
            {
                IProcess process = syscall.Thread?.Process;

                if (process == null)
                {
                    continue;
                }

                if (!syscallsPerCommandLine.ContainsKey(process))
                {
                    syscallsPerCommandLine.Add(process, 0);
                }

                ++syscallsPerCommandLine[process];
            }

            Console.WriteLine("Process Command Line: Syscalls Count");

            foreach (IProcess process in syscallsPerCommandLine.Keys)
            {
                Console.WriteLine($"{process.CommandLine}: {syscallsPerCommandLine[process]}");
            }
        }
    }
}

Mengakses data streaming

Dengan jejak syscalls yang besar, mencoba menyimpan data syscall dalam memori bisa sangat mahal, atau bahkan mungkin tidak bisa dilakukan. Kode berikut menunjukkan cara mengakses data syscall yang sama dengan cara streaming, menggantikan trace.UseSyscalls() dengan trace.UseStreaming().UseSyscalls():

using Microsoft.Windows.EventTracing;
using Microsoft.Windows.EventTracing.Processes;
using Microsoft.Windows.EventTracing.Syscalls;
using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        if (args.Length != 1)
        {
            Console.Error.WriteLine("Usage: <trace.etl>");
            return;
        }

        using (ITraceProcessor trace = TraceProcessor.Create(args[0]))
        {
            IPendingResult<IThreadDataSource> pendingThreadData = trace.UseThreads();

            Dictionary<IProcess, int> syscallsPerCommandLine = new Dictionary<IProcess, int>();

            trace.UseStreaming().UseSyscalls(ConsumerSchedule.SecondPass, context =>
            {
                Syscall syscall = context.Data;
                IProcess process = syscall.GetThread(pendingThreadData.Result)?.Process;

                if (process == null)
                {
                    return;
                }

                if (!syscallsPerCommandLine.ContainsKey(process))
                {
                    syscallsPerCommandLine.Add(process, 0);
                }

                ++syscallsPerCommandLine[process];
            });

            trace.Process();

            Console.WriteLine("Process Command Line: Syscalls Count");

            foreach (IProcess process in syscallsPerCommandLine.Keys)
            {
                Console.WriteLine($"{process.CommandLine}: {syscallsPerCommandLine[process]}");
            }
        }
    }
}

Cara kerja streaming

Secara default, semua data streaming disediakan selama pelacakan pertama, dan data yang di-buffer dari sumber lain tidak tersedia. Contoh di atas menunjukkan cara menggabungkan streaming dengan buffering – data utas di-buffer sebelum data syscall dialirkan. Akibatnya, penelusuran harus dibaca dua kali - sekali untuk mendapatkan data utas yang dibuffer, dan kedua kali untuk mengakses data syscall yang dialirkan dengan data utas yang dibuffer sekarang tersedia. Untuk menggabungkan streaming dan buffering dengan cara ini, contoh meneruskan ConsumerSchedule.SecondPass ke lacak.UseStreaming().UseSyscalls(), yang menyebabkan pengolahan syscall terjadi pada pengulangan kedua melalui lacak tersebut. Dengan menjalankan pass kedua, panggilan balik syscall dapat mengakses hasil yang tertunda dari pelacakan UseThreads() saat memproses setiap syscall. Tanpa argumen opsional ini, streaming syscall akan dijalankan pada lintasan pertama melalui jejak (hanya akan ada satu lintasan), dan hasil yang tertunda dari trace.UseThreads() tidak akan tersedia. Dalam hal ini, panggilan balik masih akan memiliki akses ke ThreadId dari syscall, tetapi tidak akan memiliki akses ke proses untuk utas (karena utas untuk memproses data penautan disediakan melalui peristiwa lain yang mungkin belum diproses).

Beberapa perbedaan utama dalam penggunaan antara buffering dan streaming:

  1. Buffering mengembalikan IPendingResult<T>, dan hasil yang disimpannya hanya tersedia sebelum jejak diproses. Setelah jejak diproses, hasilnya dapat dijumlahkan menggunakan teknik seperti foreach dan LINQ.
  2. Streaming mengembalikan kekosongan dan sebaliknya mengambil argumen panggilan balik. Ini memanggil panggilan balik sekali saat setiap item tersedia. Karena data tidak di-buffer, tidak pernah ada daftar hasil untuk dijumlahkan dengan foreach atau LINQ - panggilan balik streaming perlu buffer bagian mana pun dari data yang ingin disimpan untuk digunakan setelah pemrosesan selesai.
  3. Kode untuk memproses data yang dibuffer muncul setelah panggilan ke trace.Process(), ketika hasil yang masih menunggu tersedia.
  4. Kode untuk memproses data streaming muncul sebelum panggilan ke trace.Process(), sebagai callback ke metode trace.UseStreaming.Use...().
  5. Seorang konsumen streaming dapat memilih untuk hanya memproses sebagian dari streaming dan membatalkan panggilan balik di masa mendatang dengan memanggil context.Cancel(). Konsumen yang melakukan buffering selalu diberikan daftar lengkap yang sudah di-buffer.

Data streaming berkorelasi

Terkadang data pelacakan datang dalam urutan peristiwa - misalnya, syscalls dicatat melalui peristiwa masuk dan keluar terpisah, tetapi data gabungan dari kedua peristiwa dapat lebih membantu. Metode pelacakan trace.UseStreaming().UseSyscalls() menghubungkan data dari kedua peristiwa ini dan menyediakannya saat data pasangan tersebut tersedia. Beberapa jenis data berkorelasi dapat diakses melalui trace.UseStreaming():

Kode Deskripsi
bekas. UseStreaming(). UseContextSwitchData() Mengalirkan data pergantian konteks yang berkorelasi (dari peristiwa kompak dan non-kompak, dengan SwitchInThreadIds yang lebih akurat daripada peristiwa mentah yang non-kompak).
bekas. UseStreaming(). UseScheduledTasks() Menyediakan data tugas terjadwal terkoordinasi.
trace. UseStreaming(). UseSyscalls() Menyalurkan data panggilan sistem yang berkorelasi.
bekas. UseStreaming(). UseWindowInFocus() Mengalirkan data window-in-focus yang berkorelasi.

Acara streaming khusus

Selain itu, Trace.UseStreaming() menyediakan peristiwa yang diparsing untuk sejumlah jenis peristiwa mandiri yang berbeda.

Kode Deskripsi
pelacakan.UseStreaming().UseLastBranchRecordEvents() Streaming mengurai peristiwa rekaman cabang terakhir (LBR).
lacak.UseStreaming().UseReadyThreadEvents() Streaming peristiwa alur siap diurai.
bekas. UseStreaming(). UseThreadCreateEvents() Aliran utas yang diurai membuat peristiwa.
lacak.UseStreaming().UseThreadExitEvents() Streaming peristiwa keluar utas yang diurai.
bekas. UseStreaming(). UseThreadRundownStartEvents() Mengalirkan peristiwa mulai penguraian rangkaian utas.
bekas. UseStreaming(). UseThreadRundownStopEvents() Streaming penghentian peristiwa rundown utas yang diproses.
pelacakan.UseStreaming().UseThreadSetNameEvents() Aliran peristiwa penamaan kumpulan utas yang telah diurai.

Peristiwa streaming dasar untuk data yang berkorelasi

Akhirnya, lacak. UseStreaming() juga menyediakan peristiwa mendasar yang digunakan untuk menghubungkan data dalam daftar di atas. Peristiwa yang mendasar ini adalah:

Kode Deskripsi Disertakan dalam
bekas. UseStreaming(). UseCompactContextSwitchEvents() Streaming mengurai peristiwa pengalihan konteks ringkas. bekas. UseStreaming(). UseContextSwitchData()
bekas. UseStreaming(). UseContextSwitchEvents() Streaming peristiwa pengalihan konteks yang diurai. SwitchInThreadIds mungkin tidak akurat dalam beberapa kasus. bekas. UseStreaming(). UseContextSwitchData()
bekas. UseStreaming(). UseFocusChangeEvents() Mengalirkan peristiwa perubahan fokus jendela yang telah diurai. bekas. UseStreaming(). UseWindowInFocus()
bekas. UseStreaming(). UseScheduledTaskStartEvents() Mengalirkan peristiwa dimulainya tugas terjadwal yang telah diurai. bekas. UseStreaming(). UseScheduledTasks()
Trace.UseStreaming().UseScheduledTaskStopEvents() Streaming acara berhenti tugas terjadwal yang diurai. bekas. UseStreaming(). UseScheduledTasks()
bekas. UseStreaming(). UseScheduledTaskTriggerEvents() Memproses peristiwa pemicu tugas terjadwal yang telah diurai. bekas. UseStreaming(). UseScheduledTasks()
bekas. UseStreaming(). UseSessionLayerSetActiveWindowEvents() Stream mengurai sesi-lapisan yang mengatur peristiwa jendela aktif. bekas. UseStreaming(). UseWindowInFocus()
bekas. UseStreaming(). UseSyscallEnterEvents() Streams parsed syscall masukkan peristiwa. trace. UseStreaming(). UseSyscalls()
bekas. UseStreaming(). UseSyscallExitEvents() Mengalirkan peristiwa keluar syscall yang telah diurai. trace. UseStreaming(). UseSyscalls()

Langkah Selanjutnya

Dalam tutorial ini, Anda mempelajari cara menggunakan streaming untuk mengakses data pelacakan segera dan menggunakan lebih sedikit memori.

Langkah selanjutnya adalah melihat dan mengakses data yang Anda inginkan dari rekam jejak Anda. Lihat sampel untuk beberapa ide. Perhatikan bahwa tidak semua jejak menyertakan semua jenis data yang didukung.