mirror of
https://github.com/facebook/sapling.git
synced 2024-10-05 14:28:17 +03:00
95f27884de
Summary: The documentation didn't mention what the nametag emoji meant, fix this. Reviewed By: chadaustin Differential Revision: D46987216 fbshipit-source-id: 7c001cfc2b6268cfe9dd9e6514a68494bec54ed2
296 lines
10 KiB
Python
296 lines
10 KiB
Python
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
#
|
|
# This software may be used and distributed according to the terms of the
|
|
# GNU General Public License version 2.
|
|
|
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
|
|
|
import argparse
|
|
import os
|
|
import pathlib
|
|
import subprocess
|
|
import sys
|
|
from typing import List, Union
|
|
|
|
from . import subcmd as subcmd_mod
|
|
from .cmd_util import require_checkout
|
|
from .subcmd import Subcmd
|
|
|
|
|
|
trace_cmd = subcmd_mod.Decorator()
|
|
|
|
|
|
def get_trace_stream_command() -> pathlib.Path:
|
|
# TODO(T111405470) Rewrite in rust so we can avoid hardcoding these paths
|
|
try:
|
|
return pathlib.Path(os.environ["EDENFS_TRACE_STREAM"])
|
|
except KeyError:
|
|
if sys.platform == "win32":
|
|
return pathlib.Path("C:/tools/eden/libexec/trace_stream.exe")
|
|
return pathlib.Path("/usr/local/libexec/eden/eden_trace_stream")
|
|
|
|
|
|
def execute_cmd(arg_list: List[Union[pathlib.Path, str]]) -> int:
|
|
if sys.platform == "win32":
|
|
return subprocess.call(arg_list)
|
|
else:
|
|
encoded_args = [os.fsencode(arg) for arg in arg_list]
|
|
os.execv(
|
|
arg_list[0],
|
|
encoded_args,
|
|
)
|
|
|
|
|
|
@trace_cmd("hg", "Trace hg object fetches")
|
|
class TraceHgCommand(Subcmd):
|
|
DESCRIPTION = """Trace EdenFS object fetches from Mercurial.
|
|
|
|
With the --retroactive flag, this will print a list of the past N object fetches.
|
|
By default, it will print up to N=100 events, but this can be configured with the
|
|
following config option:
|
|
[telemetry]
|
|
activitybuffer-max-events = 100
|
|
|
|
Events are encoded using the following emojis:
|
|
|
|
Event Type:
|
|
\u21E3 START
|
|
\u2193 FINISH
|
|
|
|
Resource Type:
|
|
\U0001F954 Blob (file content)
|
|
\U0001F332 Tree (directory content)
|
|
\U0001F4DB Blob Metadata (sha1, size, blake3)
|
|
|
|
Import Priority (--verbose):
|
|
\U0001F7E5 LOW
|
|
\U0001F536 NORMAL
|
|
\U0001F7E2 HIGH
|
|
|
|
Import Cause (--verbose):
|
|
\u2753 UNKNOWN
|
|
\U0001F4C1 FS
|
|
\U0001F4E0 THRIFT
|
|
\U0001F4C5 PREFETCH
|
|
"""
|
|
# pyre-fixme[15]: Type typing.Type[argparse.RawDescriptionHelpFormatter] is not a
|
|
# subtype of the overridden attribute typing.Optional[argparse.HelpFormatter]
|
|
FORMATTER = argparse.RawDescriptionHelpFormatter
|
|
|
|
def setup_parser(self, parser: argparse.ArgumentParser) -> None:
|
|
parser.add_argument(
|
|
"checkout", default=None, nargs="?", help="Path to the checkout"
|
|
)
|
|
parser.add_argument(
|
|
"--verbose",
|
|
action="store_true",
|
|
default=False,
|
|
help="Show import priority and cause",
|
|
)
|
|
parser.add_argument(
|
|
"--retroactive",
|
|
action="store_true",
|
|
default=False,
|
|
help="Provide stored hg events (from a buffer) across past changes",
|
|
)
|
|
|
|
async def run(self, args: argparse.Namespace) -> int:
|
|
instance, checkout, _rel_path = require_checkout(args, args.checkout)
|
|
trace_stream_command = get_trace_stream_command()
|
|
return execute_cmd(
|
|
[
|
|
trace_stream_command,
|
|
"--mountRoot",
|
|
checkout.path,
|
|
"--trace=hg",
|
|
f"--verbose={'true' if args.verbose else 'false'}",
|
|
f"--retroactive={'true' if args.retroactive else 'false'}",
|
|
]
|
|
)
|
|
|
|
|
|
@trace_cmd("fs", "Monitor filesystem requests.")
|
|
class TraceFsCommand(Subcmd):
|
|
def setup_parser(self, parser: argparse.ArgumentParser) -> None:
|
|
parser.add_argument(
|
|
"checkout", default=None, nargs="?", help="Path to the checkout"
|
|
)
|
|
parser.add_argument(
|
|
"--reads",
|
|
action="store_true",
|
|
default=False,
|
|
help="Limit trace to read operations",
|
|
)
|
|
parser.add_argument(
|
|
"--writes",
|
|
action="store_true",
|
|
default=False,
|
|
help="Limit trace to write operations",
|
|
)
|
|
|
|
async def run(self, args: argparse.Namespace) -> int:
|
|
instance, checkout, _rel_path = require_checkout(args, args.checkout)
|
|
trace_stream_command = get_trace_stream_command()
|
|
return execute_cmd(
|
|
[
|
|
trace_stream_command,
|
|
"--mountRoot",
|
|
checkout.path,
|
|
"--trace=fs",
|
|
f"--reads={'true' if args.reads else 'false'}",
|
|
f"--writes={'true' if args.writes else 'false'}",
|
|
]
|
|
)
|
|
|
|
|
|
@trace_cmd("inode", "Monitor inode state changes (loads and materializations).")
|
|
class TraceInodeCommand(Subcmd):
|
|
DESCRIPTION = """Trace EdenFS inode state changes including inode loads and materializations.
|
|
|
|
With the --retroactive flag, this will print a list of the past N inode changes.
|
|
By default, it will print up to N=100 events, but this can be configured with the
|
|
following config option:
|
|
[telemetry]
|
|
activitybuffer-max-events = 100
|
|
|
|
Loading an inode refers to fetching state for the inode to store into memory.
|
|
While loading can some times cause fetching data contents for an inode, this is
|
|
not always the case, and fetching can sometimes happen in other cases. Content
|
|
data fetches from hg servers can be traced with the eden trace hg command. Note:
|
|
loading an inode will cause its parent inode to be loaded if it isn't already.
|
|
|
|
Materializing an inode refers to modifying the inode's data such that no source
|
|
control object ID can be used to refer to the inode's data. This causes the
|
|
inode's data to be saved locally in EdenFS's overlay and causes further
|
|
materializations of the inode's parent. Note: this means one materialization
|
|
will cause materializations in parent inodes until a previously materialized
|
|
parent inode is reached (this may materialize inodes all the way to the root).
|
|
|
|
Further definitions regarding inodes state changes can be found at
|
|
https://github.com/facebookexperimental/eden/blob/main/eden/fs/docs/Glossary.md
|
|
|
|
Events for this command are encoded using the following emojis/letters:
|
|
|
|
Event Progress:
|
|
\u21E3 START
|
|
\u2193 FINISH
|
|
\u26A0 FAILURE
|
|
|
|
Resource Type:
|
|
\U0001F954 BLOB/FILE
|
|
\U0001F332 TREE/DIRECTORY
|
|
|
|
Event Type
|
|
L LOAD
|
|
M MATERIALIZE
|
|
"""
|
|
# pyre-fixme[15]: Type typing.Type[argparse.RawDescriptionHelpFormatter] is not a
|
|
# subtype of the overridden attribute typing.Optional[argparse.HelpFormatter]
|
|
FORMATTER = argparse.RawDescriptionHelpFormatter
|
|
|
|
def setup_parser(self, parser: argparse.ArgumentParser) -> None:
|
|
parser.add_argument(
|
|
"checkout", default=None, nargs="?", help="Path to the checkout"
|
|
)
|
|
parser.add_argument(
|
|
"--retroactive",
|
|
action="store_true",
|
|
default=False,
|
|
help="Provide stored inode events (from a buffer) across past changes",
|
|
)
|
|
|
|
async def run(self, args: argparse.Namespace) -> int:
|
|
instance, checkout, _rel_path = require_checkout(args, args.checkout)
|
|
trace_stream_command = get_trace_stream_command()
|
|
return execute_cmd(
|
|
[
|
|
trace_stream_command,
|
|
"--mountRoot",
|
|
checkout.path,
|
|
"--trace=inode",
|
|
f"--retroactive={'true' if args.retroactive else 'false'}",
|
|
]
|
|
)
|
|
|
|
|
|
@trace_cmd("thrift", "Monitor Thrift requests.")
|
|
class TraceThriftCmd(Subcmd):
|
|
DESCRIPTION = """Trace thrift requests made to EdenFS.
|
|
|
|
With the --retroactive flag, this will print a list of the past N thrift requests.
|
|
By default, it will print up to N=100 events, but this can be configured with the
|
|
following config option:
|
|
[telemetry]
|
|
activitybuffer-max-events = 100
|
|
|
|
A '+' represents a thrift call starting, and a '-' represents it's end. Additionally,
|
|
the thrift request ID is displayed along with what process id (pid) the call was made
|
|
from. Finally, the thrift method name and duration for how long the thrift call took
|
|
are displayed as well.
|
|
"""
|
|
|
|
# pyre-fixme[15]: Type typing.Type[argparse.RawDescriptionHelpFormatter] is not a
|
|
# subtype of the overridden attribute typing.Optional[argparse.HelpFormatter]
|
|
FORMATTER = argparse.RawDescriptionHelpFormatter
|
|
|
|
def setup_parser(self, parser: argparse.ArgumentParser) -> None:
|
|
parser.add_argument(
|
|
"checkout", default=None, nargs="?", help="Path to the checkout"
|
|
)
|
|
parser.add_argument(
|
|
"--retroactive",
|
|
action="store_true",
|
|
default=False,
|
|
help="Provide stored thrift request events (from a buffer) across past changes",
|
|
)
|
|
|
|
async def run(self, args: argparse.Namespace) -> int:
|
|
instance, checkout, _rel_path = require_checkout(args, args.checkout)
|
|
trace_stream_command = get_trace_stream_command()
|
|
return execute_cmd(
|
|
[
|
|
trace_stream_command,
|
|
"--mountRoot",
|
|
checkout.path,
|
|
"--trace=thrift",
|
|
f"--retroactive={'true' if args.retroactive else 'false'}",
|
|
]
|
|
)
|
|
|
|
|
|
@trace_cmd("task", "Monitor tasks in EdenFS daemon")
|
|
class TraceTaskCmd(Subcmd):
|
|
DESCRIPTION = """Trace tasks happening inside EdenFS daemon. The tasks
|
|
must be pre-instrumented.
|
|
|
|
Use `--chrome-trace` flag if you want to analyze the output with Chrome
|
|
trace tools.
|
|
"""
|
|
|
|
# pyre-fixme[15]: Type typing.Type[argparse.RawDescriptionHelpFormatter] is not a
|
|
# subtype of the overridden attribute typing.Optional[argparse.HelpFormatter]
|
|
FORMATTER = argparse.RawDescriptionHelpFormatter
|
|
|
|
def setup_parser(self, parser: argparse.ArgumentParser) -> None:
|
|
parser.add_argument(
|
|
"checkout", default=None, nargs="?", help="Path to the checkout"
|
|
)
|
|
parser.add_argument(
|
|
"--chrome-trace",
|
|
action="store_true",
|
|
default=False,
|
|
help="Set the output in Chrome trace format",
|
|
)
|
|
|
|
async def run(self, args: argparse.Namespace) -> int:
|
|
instance, checkout, _rel_path = require_checkout(args, args.checkout)
|
|
trace_stream_command = get_trace_stream_command()
|
|
return execute_cmd(
|
|
[
|
|
trace_stream_command,
|
|
"--mountRoot",
|
|
checkout.path,
|
|
f"--trace={'task-chrome-trace' if args.chrome_trace else 'task'}",
|
|
]
|
|
)
|