Author: jdevlieghere Date: Mon Jul 8 14:38:34 2019 New Revision: 365391 URL: http://llvm.org/viewvc/llvm-project?rev=365391&view=rev Log: Remove lldb-perf
As discussed offline, this tool is no longer used or maintained, and doesn't provide the right abstraction for performance tracking in lldb. Differential revision: https://reviews.llvm.org/D64362 Removed: lldb/trunk/tools/lldb-perf/README lldb/trunk/tools/lldb-perf/common/ lldb/trunk/tools/lldb-perf/darwin/formatters/ lldb/trunk/tools/lldb-perf/darwin/sketch/sketch.cpp lldb/trunk/tools/lldb-perf/lib/ lldb/trunk/tools/lldb-perf/lldbperf.xcodeproj/ Modified: lldb/trunk/lldb.xcworkspace/contents.xcworkspacedata Modified: lldb/trunk/lldb.xcworkspace/contents.xcworkspacedata URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcworkspace/contents.xcworkspacedata?rev=365391&r1=365390&r2=365391&view=diff ============================================================================== --- lldb/trunk/lldb.xcworkspace/contents.xcworkspacedata (original) +++ lldb/trunk/lldb.xcworkspace/contents.xcworkspacedata Mon Jul 8 14:38:34 2019 @@ -7,7 +7,4 @@ <FileRef location = "group:tools/debugserver/debugserver.xcodeproj"> </FileRef> - <FileRef - location = "group:tools/lldb-perf/lldbperf.xcodeproj"> - </FileRef> </Workspace> Removed: lldb/trunk/tools/lldb-perf/README URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-perf/README?rev=365390&view=auto ============================================================================== --- lldb/trunk/tools/lldb-perf/README (original) +++ lldb/trunk/tools/lldb-perf/README (removed) @@ -1,295 +0,0 @@ - The lldb-perf infrastructure for LLDB performance testing -=========================================================== - -lldb-perf is an infrastructure meant to simplify the creation of performance -tests for the LLDB debugger. It is contained in liblldbperf.a which is part of -the standard opensource checkout of LLDB - -Its main concepts are: -- Gauges: a gauge is a thing that takes a sample. Samples include elapsed time, - memory used, and energy consumed. -- Metrics: a metric is a collection of samples that knows how to do statistics - like sum() and average(). Metrics can be extended as needed. -- Measurements: a measurement is the thing that stores an action, a gauge and - a metric. You define measurements as in âtake the time to run this functionâ, - âtake the memory to run this block of codeâ, and then after you invoke it, - your stats will automagically be there. -- Tests: a test is a sequence of steps and measurements. - -Tests cases should be added as targets to the lldbperf.xcodeproj project. It -is probably easiest to duplicate one of the existing targets. In order to -write a test based on lldb-perf, you need to subclass lldb_perf::TestCase: - -using namespace lldb_perf; - -class FormattersTest : public TestCase -{ - -Usually, you will define measurements as variables of your test case class: - -private: - // C++ formatters - TimeMeasurement<std::function<void(SBValue)>> m_dump_std_vector_measurement; - TimeMeasurement<std::function<void(SBValue)>> m_dump_std_list_measurement; - TimeMeasurement<std::function<void(SBValue)>> m_dump_std_map_measurement; - TimeMeasurement<std::function<void(SBValue)>> m_dump_std_string_measurement; - - // Cocoa formatters - TimeMeasurement<std::function<void(SBValue)>> m_dump_nsstring_measurement; - TimeMeasurement<std::function<void(SBValue)>> m_dump_nsarray_measurement; - TimeMeasurement<std::function<void(SBValue)>> m_dump_nsdictionary_measurement; - TimeMeasurement<std::function<void(SBValue)>> m_dump_nsset_measurement; - TimeMeasurement<std::function<void(SBValue)>> m_dump_nsbundle_measurement; - TimeMeasurement<std::function<void(SBValue)>> m_dump_nsdate_measurement; - -A TimeMeasurement is, obviously, a class that measures âhow much time to run -this block of codeâ. The block of code is passed as an std::function which you -can construct with a lambda! You need to give the prototype of your block of -code. In this example, we run blocks of code that take an SBValue and return -nothing. - -These blocks look like: - - m_dump_std_vector_measurement = CreateTimeMeasurement([] (SBValue value) -> void { - lldb_perf::Xcode::FetchVariable (value,1,false); - }, "std-vector", "time to dump an std::vector"); - -Here we are saying: make me a measurement named âstd-vectorâ, whose -description is âtime to dump an std::vectorâ and that takes the time required -to call lldb_perf::Xcode::FetchVariable(value,1,false). - -The Xcode class is a collection of utility functions that replicate common -Xcode patterns (FetchVariable unsurprisingly calls API functions that Xcode -could use when populating a variables view entry - the 1 means âexpand 1 level -of depthâ and the false means âdo not dump the data to stdoutâ) - -A full constructor for a TestCase looks like: - -FormattersTest () : TestCase() -{ - m_dump_std_vector_measurement = CreateTimeMeasurement([] (SBValue value) -> void { - lldb_perf::Xcode::FetchVariable (value,1,false); - }, "std-vector", "time to dump an std::vector"); - m_dump_std_list_measurement = CreateTimeMeasurement([] (SBValue value) -> void { - lldb_perf::Xcode::FetchVariable (value,1,false); - }, "std-list", "time to dump an std::list"); - m_dump_std_map_measurement = CreateTimeMeasurement([] (SBValue value) -> void { - lldb_perf::Xcode::FetchVariable (value,1,false); - }, "std-map", "time to dump an std::map"); - m_dump_std_string_measurement = CreateTimeMeasurement([] (SBValue value) -> void { - lldb_perf::Xcode::FetchVariable (value,1,false); - }, "std-string", "time to dump an std::string"); - - m_dump_nsstring_measurement = CreateTimeMeasurement([] (SBValue value) -> void { - lldb_perf::Xcode::FetchVariable (value,0,false); - }, "ns-string", "time to dump an NSString"); - - m_dump_nsarray_measurement = CreateTimeMeasurement([] (SBValue value) -> void { - lldb_perf::Xcode::FetchVariable (value,1,false); - }, "ns-array", "time to dump an NSArray"); - - m_dump_nsdictionary_measurement = CreateTimeMeasurement([] (SBValue value) -> void { - lldb_perf::Xcode::FetchVariable (value,1,false); - }, "ns-dictionary", "time to dump an NSDictionary"); - - m_dump_nsset_measurement = CreateTimeMeasurement([] (SBValue value) -> void { - lldb_perf::Xcode::FetchVariable (value,1,false); - }, "ns-set", "time to dump an NSSet"); - - m_dump_nsbundle_measurement = CreateTimeMeasurement([] (SBValue value) -> void { - lldb_perf::Xcode::FetchVariable (value,1,false); - }, "ns-bundle", "time to dump an NSBundle"); - - m_dump_nsdate_measurement = CreateTimeMeasurement([] (SBValue value) -> void { - lldb_perf::Xcode::FetchVariable (value,0,false); - }, "ns-date", "time to dump an NSDate"); -} - -Once your test case is constructed, Setup() is called on it: - - virtual bool - Setup (int argc, const char** argv) - { - m_app_path.assign(argv[1]); - m_out_path.assign(argv[2]); - m_target = m_debugger.CreateTarget(m_app_path.c_str()); - m_target.BreakpointCreateByName("main"); - SBLaunchInfo launch_info (argv); - return Launch (launch_info); - } - -Setup() returns a boolean value that indicates if setup was successful. -In Setup() you fill out a SBLaunchInfo with any needed settings for launching -your process like arguments, environment variables, working directory, and -much more. - -The last thing you want to do in setup is call Launch(): - - bool - Launch (coSBLaunchInfo &launch_info); - -This ensures your target is now alive. Make sure to have a breakpoint created. - -Once you launched, the event loop is entered. The event loop waits for stops, -and when it gets one, it calls your test caseâs TestStep() function: - - virtual void - TestStep (int counter, ActionWanted &next_action) - -the counter is the step id (a monotonically increasing counter). In TestStep() -you will essentially run your measurements and then return what you want the -driver to do by filling in the ActionWanted object named "next_action". - -Possible options are: -- continue process next_action.Continue(); -- kill process next_action.Kill(); -- Step-out on a thread next_action.StepOut(SBThread) -- step-over on a thread. next_action.StepOver(SBThread) - -If you use ActionWanted::Next() or ActionWanted::Finish() you need to specify -a thread to use. By default the TestCase class will select the first thread -that had a stop reason other than eStopReasonNone and place it into the -m_thread member variable of TestCase. This means if your test case hits a -breakpoint or steps, the thread that hit the breakpoint or finished the step -will automatically be selected in the process (m_process) and m_thread will -be set to this thread. If you have one or more threads that will stop with a -reason simultaneously, you will need to find those threads manually by -iterating through the process list and determine what to do next. - -For your convenience TestCase has m_debugger, m_target and m_process as member -variables. As state above m_thread will be filled in with the first thread -that has a stop reason. - -An example: - - virtual void - TestStep (int counter, ActionWanted &next_action) - { - case 0: - m_target.BreakpointCreateByLocation("fmts_tester.mm", 68); - next_action.Continue(); - break; - case 1: - DoTest (); - next_action.Continue(); - break; - case 2: - DoTest (); - next_action.StepOver(m_thread); - break; - -DoTest() is a function I define in my own class that calls the measurements: - void - DoTest () - { - SBThread thread_main(m_thread); - SBFrame frame_zero(thread_main.GetFrameAtIndex(0)); - - m_dump_nsarray_measurement(frame_zero.FindVariable("nsarray", lldb::eDynamicCanRunTarget)); - m_dump_nsarray_measurement(frame_zero.FindVariable("nsmutablearray", lldb::eDynamicCanRunTarget)); - - m_dump_nsdictionary_measurement(frame_zero.FindVariable("nsdictionary", lldb::eDynamicCanRunTarget)); - m_dump_nsdictionary_measurement(frame_zero.FindVariable("nsmutabledictionary", lldb::eDynamicCanRunTarget)); - - m_dump_nsstring_measurement(frame_zero.FindVariable("str0", lldb::eDynamicCanRunTarget)); - m_dump_nsstring_measurement(frame_zero.FindVariable("str1", lldb::eDynamicCanRunTarget)); - m_dump_nsstring_measurement(frame_zero.FindVariable("str2", lldb::eDynamicCanRunTarget)); - m_dump_nsstring_measurement(frame_zero.FindVariable("str3", lldb::eDynamicCanRunTarget)); - m_dump_nsstring_measurement(frame_zero.FindVariable("str4", lldb::eDynamicCanRunTarget)); - - m_dump_nsdate_measurement(frame_zero.FindVariable("me", lldb::eDynamicCanRunTarget)); - m_dump_nsdate_measurement(frame_zero.FindVariable("cutie", lldb::eDynamicCanRunTarget)); - m_dump_nsdate_measurement(frame_zero.FindVariable("mom", lldb::eDynamicCanRunTarget)); - m_dump_nsdate_measurement(frame_zero.FindVariable("dad", lldb::eDynamicCanRunTarget)); - m_dump_nsdate_measurement(frame_zero.FindVariable("today", lldb::eDynamicCanRunTarget)); - - m_dump_nsbundle_measurement(frame_zero.FindVariable("bundles", lldb::eDynamicCanRunTarget)); - m_dump_nsbundle_measurement(frame_zero.FindVariable("frameworks", lldb::eDynamicCanRunTarget)); - - m_dump_nsset_measurement(frame_zero.FindVariable("nsset", lldb::eDynamicCanRunTarget)); - m_dump_nsset_measurement(frame_zero.FindVariable("nsmutableset", lldb::eDynamicCanRunTarget)); - - m_dump_std_vector_measurement(frame_zero.FindVariable("vector", lldb::eDynamicCanRunTarget)); - m_dump_std_list_measurement(frame_zero.FindVariable("list", lldb::eDynamicCanRunTarget)); - m_dump_std_map_measurement(frame_zero.FindVariable("map", lldb::eDynamicCanRunTarget)); - - m_dump_std_string_measurement(frame_zero.FindVariable("sstr0", lldb::eDynamicCanRunTarget)); - m_dump_std_string_measurement(frame_zero.FindVariable("sstr1", lldb::eDynamicCanRunTarget)); - m_dump_std_string_measurement(frame_zero.FindVariable("sstr2", lldb::eDynamicCanRunTarget)); - m_dump_std_string_measurement(frame_zero.FindVariable("sstr3", lldb::eDynamicCanRunTarget)); - m_dump_std_string_measurement(frame_zero.FindVariable("sstr4", lldb::eDynamicCanRunTarget)); - } - -Essentially, you call your measurements as if they were functions, passing -them arguments and all, and they will do the right thing with gathering stats. - -The last step is usually to KILL the inferior and bail out: - - virtual ActionWanted - TestStep (int counter) - { -... - case 9: - DoTest (); - next_action.Continue(); - break; - case 10: - DoTest (); - next_action.Continue(); - break; - default: - next_action.Kill(); - break; - } - - -At the end, you define a Results() function: - - void - Results () - { - CFCMutableArray array; - m_dump_std_vector_measurement.Write(array); - m_dump_std_list_measurement.Write(array); - m_dump_std_map_measurement.Write(array); - m_dump_std_string_measurement.Write(array); - - m_dump_nsstring_measurement.Write(array); - m_dump_nsarray_measurement.Write(array); - m_dump_nsdictionary_measurement.Write(array); - m_dump_nsset_measurement.Write(array); - m_dump_nsbundle_measurement.Write(array); - m_dump_nsdate_measurement.Write(array); - - CFDataRef xmlData = CFPropertyListCreateData (kCFAllocatorDefault, - array.get(), - kCFPropertyListXMLFormat_v1_0, - 0, - NULL); - - CFURLRef file = CFURLCreateFromFileSystemRepresentation (NULL, - (const UInt8*)m_out_path.c_str(), - m_out_path.size(), - FALSE); - - CFURLWriteDataAndPropertiesToResource(file,xmlData,NULL,NULL); - } - -For now, pretty much copy this and just call Write() on all your measurements. -I plan to move this higher in the hierarchy (e.g. make a -TestCase::Write(filename) fairly soon). - -Your main() will look like: - -int main(int argc, const char * argv[]) -{ - MyTest test; - TestCase::Run (test, argc, argv); - return 0; -} - -If you are debugging your test, before Run() call - - test.SetVerbose(true); - -Feel free to send any questions and ideas for improvements. Removed: lldb/trunk/tools/lldb-perf/darwin/sketch/sketch.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-perf/darwin/sketch/sketch.cpp?rev=365390&view=auto ============================================================================== --- lldb/trunk/tools/lldb-perf/darwin/sketch/sketch.cpp (original) +++ lldb/trunk/tools/lldb-perf/darwin/sketch/sketch.cpp (removed) @@ -1,329 +0,0 @@ -//===-- sketch.cpp ----------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include <CoreFoundation/CoreFoundation.h> - -#include "lldb-perf/lib/Measurement.h" -#include "lldb-perf/lib/Metric.h" -#include "lldb-perf/lib/TestCase.h" -#include "lldb-perf/lib/Timer.h" -#include "lldb-perf/lib/Xcode.h" - -#include <fstream> -#include <getopt.h> -#include <iostream> -#include <unistd.h> - -using namespace lldb_perf; - -static struct option g_long_options[] = { - {"verbose", no_argument, NULL, 'v'}, - {"sketch", required_argument, NULL, 'c'}, - {"foobar", required_argument, NULL, 'f'}, - {"out-file", required_argument, NULL, 'o'}, - {NULL, 0, NULL, 0}}; - -class SketchTest : public TestCase { -public: - SketchTest() - : m_fetch_frames_measurement( - [this]() -> void { - Xcode::FetchFrames(GetProcess(), false, false); - }, - "fetch-frames", - "time to dump backtrace for every frame in every thread"), - m_file_line_bp_measurement( - [this](const char *file, uint32_t line) -> void { - Xcode::CreateFileLineBreakpoint(GetTarget(), file, line); - }, - "file-line-bkpt", "time to set a breakpoint given a file and line"), - m_fetch_modules_measurement( - [this]() -> void { Xcode::FetchModules(GetTarget()); }, - "fetch-modules", "time to get info for all modules in the process"), - m_fetch_vars_measurement( - [this](int depth) -> void { - SBProcess process(GetProcess()); - auto threads_count = process.GetNumThreads(); - for (size_t thread_num = 0; thread_num < threads_count; - thread_num++) { - SBThread thread(process.GetThreadAtIndex(thread_num)); - SBFrame frame(thread.GetFrameAtIndex(0)); - Xcode::FetchVariables(frame, depth, GetVerbose()); - } - }, - "fetch-vars", - "time to dump variables for the topmost frame in every thread"), - m_run_expr_measurement( - [this](SBFrame frame, const char *expr) -> void { - SBValue value( - frame.EvaluateExpression(expr, lldb::eDynamicCanRunTarget)); - Xcode::FetchVariable(value, 0, GetVerbose()); - }, - "run-expr", - "time to evaluate an expression and display the result") { - m_app_path.clear(); - m_out_path.clear(); - m_doc_path.clear(); - m_print_help = false; - } - - virtual ~SketchTest() {} - - virtual bool ParseOption(int short_option, const char *optarg) { - switch (short_option) { - case 0: - return false; - - case -1: - return false; - - case '?': - case 'h': - m_print_help = true; - break; - - case 'v': - SetVerbose(true); - break; - - case 'c': { - SBFileSpec file(optarg); - if (file.Exists()) - SetExecutablePath(optarg); - else - fprintf(stderr, "error: file specified in --sketch (-c) option doesn't " - "exist: '%s'\n", - optarg); - } break; - - case 'f': { - SBFileSpec file(optarg); - if (file.Exists()) - SetDocumentPath(optarg); - else - fprintf(stderr, "error: file specified in --foobar (-f) option doesn't " - "exist: '%s'\n", - optarg); - } break; - - case 'o': - SetResultFilePath(optarg); - break; - - default: - m_print_help = true; - fprintf(stderr, "error: unrecognized option %c\n", short_option); - break; - } - return true; - } - - virtual struct option *GetLongOptions() { return g_long_options; } - - virtual bool Setup(int &argc, const char **&argv) { - TestCase::Setup(argc, argv); - bool error = false; - - if (GetExecutablePath() == NULL) { - // --sketch is mandatory - error = true; - fprintf(stderr, "error: the '--sketch=PATH' option is mandatory\n"); - } - - if (GetDocumentPath() == NULL) { - // --foobar is mandatory - error = true; - fprintf(stderr, "error: the '--foobar=PATH' option is mandatory\n"); - } - - if (error || GetPrintHelp()) { - puts(R"( - NAME - lldb_perf_sketch -- a tool that measures LLDB peformance while debugging sketch. - - SYNOPSIS - lldb_perf_sketch --sketch=PATH --foobar=PATH [--out-file=PATH --verbose] - - DESCRIPTION - Runs a set of static timing and memory tasks against sketch and outputs results - to a plist file. - )"); - } - - if (error) { - exit(1); - } - lldb::SBLaunchInfo launch_info = GetLaunchInfo(); - m_target = m_debugger.CreateTarget(m_app_path.c_str()); - m_file_line_bp_measurement("SKTDocument.m", 245); - m_file_line_bp_measurement("SKTDocument.m", 283); - m_file_line_bp_measurement("SKTText.m", 326); - return Launch(launch_info); - } - - lldb::SBLaunchInfo GetLaunchInfo() { - const char *file_arg = m_doc_path.c_str(); - const char *persist_arg = "-ApplePersistenceIgnoreState"; - const char *persist_skip = "YES"; - const char *empty = nullptr; - const char *args[] = {file_arg, persist_arg, persist_skip, empty}; - return SBLaunchInfo(args); - } - - void DoTest() { - m_fetch_frames_measurement(); - m_fetch_modules_measurement(); - m_fetch_vars_measurement(1); - } - - virtual void TestStep(int counter, ActionWanted &next_action) { - static int launch = 1; - switch (counter % 10) { - case 0: { - DoTest(); - if (counter == 0) - m_file_line_bp_measurement("SKTDocument.m", 254); - next_action.Continue(); - } break; - - case 1: { - DoTest(); - m_run_expr_measurement(m_thread.GetFrameAtIndex(0), "properties"); - m_run_expr_measurement(m_thread.GetFrameAtIndex(0), - "[properties description]"); - m_run_expr_measurement(m_thread.GetFrameAtIndex(0), "typeName"); - m_run_expr_measurement(m_thread.GetFrameAtIndex(0), "data"); - m_run_expr_measurement(m_thread.GetFrameAtIndex(0), "[data description]"); - next_action.Continue(); - } break; - - case 2: { - DoTest(); - next_action.Continue(); - } break; - - case 3: { - DoTest(); - next_action.StepOver(m_thread); - } break; - - case 4: { - DoTest(); - m_run_expr_measurement(m_thread.GetFrameAtIndex(0), "layoutManager"); - m_run_expr_measurement(m_thread.GetFrameAtIndex(0), "contents"); - next_action.StepOver(m_thread); - } break; - - case 5: { - DoTest(); - next_action.StepOver(m_thread); - } break; - - case 6: { - DoTest(); - next_action.StepOver(m_thread); - } break; - - case 7: { - DoTest(); - m_run_expr_measurement(m_thread.GetFrameAtIndex(0), "@\"an NSString\""); - m_run_expr_measurement(m_thread.GetFrameAtIndex(0), - "[(id)@\"an NSString\" description]"); - m_run_expr_measurement(m_thread.GetFrameAtIndex(0), "@[@1,@2,@3]"); - next_action.StepOut(m_thread); - } break; - - case 8: { - DoTest(); - m_run_expr_measurement(m_thread.GetFrameAtIndex(0), - "[graphics description]"); - m_run_expr_measurement(m_thread.GetFrameAtIndex(0), - "[selectionIndexes description]"); - m_run_expr_measurement( - m_thread.GetFrameAtIndex(0), - "(BOOL)NSIntersectsRect(rect, graphicDrawingBounds)"); - } - next_action.CallNext(); - break; - case 9: - if (++launch < 10) - next_action.Relaunch(GetLaunchInfo()); - else - next_action.Kill(); - break; - - default: { next_action.Kill(); } break; - } - } - - virtual void WriteResults(Results &results) { - m_fetch_frames_measurement.WriteAverageAndStandardDeviation(results); - m_file_line_bp_measurement.WriteAverageAndStandardDeviation(results); - m_fetch_modules_measurement.WriteAverageAndStandardDeviation(results); - m_fetch_vars_measurement.WriteAverageAndStandardDeviation(results); - m_run_expr_measurement.WriteAverageAndStandardDeviation(results); - results.Write(GetResultFilePath()); - } - - void SetExecutablePath(const char *str) { - if (str) - m_app_path.assign(str); - } - - const char *GetExecutablePath() { - if (m_app_path.empty()) - return NULL; - return m_app_path.c_str(); - } - - void SetDocumentPath(const char *str) { - if (str) - m_doc_path.assign(str); - } - - const char *GetDocumentPath() { - if (m_doc_path.empty()) - return NULL; - return m_doc_path.c_str(); - } - - void SetResultFilePath(const char *str) { - if (str) - m_out_path.assign(str); - } - - const char *GetResultFilePath() { - if (m_out_path.empty()) - return "/dev/stdout"; - return m_out_path.c_str(); - } - - bool GetPrintHelp() { return m_print_help; } - -private: - Measurement<lldb_perf::TimeGauge, std::function<void()>> - m_fetch_frames_measurement; - Measurement<lldb_perf::TimeGauge, std::function<void(const char *, uint32_t)>> - m_file_line_bp_measurement; - Measurement<lldb_perf::TimeGauge, std::function<void()>> - m_fetch_modules_measurement; - Measurement<lldb_perf::TimeGauge, std::function<void(int)>> - m_fetch_vars_measurement; - Measurement<lldb_perf::TimeGauge, std::function<void(SBFrame, const char *)>> - m_run_expr_measurement; - - std::string m_app_path; - std::string m_doc_path; - std::string m_out_path; - bool m_print_help; -}; - -int main(int argc, const char *argv[]) { - SketchTest test; - return TestCase::Run(test, argc, argv); -} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits