Skip to content

Commit

Permalink
add includeTasks to served/getInfo request
Browse files Browse the repository at this point in the history
lists currently running and recently exited fibers
  • Loading branch information
WebFreak001 committed Dec 11, 2023
1 parent 9895a50 commit 03100c1
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 52 deletions.
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,7 @@ interface ServedInfoParams
{
includeConfig?: boolean;
includeIndex?: boolean;
includeTasks?: boolean;
}

interface ServedInfoResponse
Expand All @@ -650,7 +651,7 @@ interface ServedInfoResponse

/**
* Only included if `ServedInfoParams.includeConfig` is true.
*
*
* Contains the entire config object, e.g. `{"d":{...}, ...}`
*/
currentConfiguration?: Configuration;
Expand All @@ -676,6 +677,28 @@ interface ServedInfoResponse
* `selected` is set to true, or -1 for global workspace.
*/
selectedWorkspaceIndex: number;

/**
* Only included if `ServedInfoParams.includeTasks` is true.
*
* List of currently running and recently done LSP requests and tasks
*/
runningTasks: {
/** task name (in most cases function name or LSP request name) */
name: string,
/** Number of seconds before now (float) when the task was queued */
queued: number,
/** Number of seconds before now (float) when the task was first started */
started: number,
/** Number of seconds before now (float) when the task ended - 0 for running tasks */
ended: number,
/** true if currently ongoing (e.g. yielding) */
running: boolean,
/** Number of (re)entries */
numSteps: number,
/** Number of seconds that this fiber was running in total */
timeSpent: number,
}[]
}
```

Expand Down
8 changes: 8 additions & 0 deletions protocol/source/served/lsp/protocol.d
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,14 @@ struct RequestMessageRaw
{
return text("RequestMessage(", method, ": ", paramsJson, ")");
}

/// Descriptive name for this request/notification
string fiberName() const @safe pure
{
return id.isNone
? "Notification: " ~ method
: "Request#" ~ id.deref.toString ~ ": " ~ method;
}
}

///
Expand Down
20 changes: 11 additions & 9 deletions serverbase/source/served/serverbase.d
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ mixin template LanguageServerRouter(alias ExtensionModule, LanguageServerConfig
res.resultJson = initResult.serializeJson;
trace("Initialized");
serverInitializeCalled = true;
pushFiber({
pushFiber("Request: initialize", {
Fiber.yield();
processRequestObservers(msg, initResult);
});
Expand Down Expand Up @@ -172,12 +172,14 @@ mixin template LanguageServerRouter(alias ExtensionModule, LanguageServerConfig
partialResultToken = v.partialResultToken;
}

string fiberName = msg.fiberName;

int working = 0;
string[] partialResults;
void handlePartialWork(Symbol, Arguments)(Symbol fn, Arguments args)
{
working++;
pushFiber({
pushFiber(fiberName ~ " (partial)", {
scope (exit)
working--;
auto thisId = working;
Expand All @@ -196,7 +198,7 @@ mixin template LanguageServerRouter(alias ExtensionModule, LanguageServerConfig
void handlePartialIterator(Symbol, Arguments)(Symbol fn, Arguments args)
{
working++;
pushFiber({
pushFiber(fiberName ~ " (iterator)", {
scope (exit)
working--;
auto thisId = working;
Expand Down Expand Up @@ -439,10 +441,10 @@ mixin template LanguageServerRouter(alias ExtensionModule, LanguageServerConfig
__gshared FiberManager fibers;
__gshared Mutex fibersMutex;

void pushFiber(T)(T callback, int pages = serverConfig.defaultPages, string file = __FILE__, int line = __LINE__)
void pushFiber(T)(string name, T callback, int pages = serverConfig.defaultPages, string file = __FILE__, int line = __LINE__)
{
synchronized (fibersMutex)
fibers.put(new Fiber(callback, serverConfig.fiberPageSize * pages), file, line);
fibers.put(name, new Fiber(callback, serverConfig.fiberPageSize * pages), file, line);
}

RPCProcessor rpc;
Expand Down Expand Up @@ -536,13 +538,13 @@ mixin template LanguageServerRouter(alias ExtensionModule, LanguageServerConfig
}
}

fibers ~= rpc;
fibers.put("RPC manager", rpc);

spawnFiberImpl = (&pushFiber!(void delegate())).toDelegate;
defaultFiberPages = serverConfig.defaultPages;

static if (is(typeof(ExtensionModule.parallelMain)))
pushFiber(&ExtensionModule.parallelMain);
pushFiber("parallelMain", &ExtensionModule.parallelMain);

while (rpc.state != Fiber.State.TERM)
{
Expand All @@ -552,9 +554,9 @@ mixin template LanguageServerRouter(alias ExtensionModule, LanguageServerConfig
// Log on client side instead! (vscode setting: "serve-d.trace.server": "verbose")
//trace("Message: ", msg);
if (!msg.id.isNone)
pushFiber(gotRequest(msg));
pushFiber(msg.fiberName, gotRequest(msg));
else
pushFiber(gotNotify(msg));
pushFiber(msg.fiberName, gotNotify(msg));
}
Thread.sleep(10.msecs);
synchronized (fibersMutex)
Expand Down
10 changes: 5 additions & 5 deletions serverbase/source/served/utils/async.d
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ import served.utils.fibermanager;
import std.datetime.stopwatch : msecs, StopWatch;
import std.experimental.logger;

__gshared void delegate(void delegate(), int pages, string file, int line) spawnFiberImpl;
__gshared void delegate(string name, void delegate(), int pages, string file, int line) spawnFiberImpl;
__gshared int defaultFiberPages = 20;
__gshared int timeoutID;
__gshared Timeout[] timeouts;
__gshared Mutex timeoutsMutex;

void spawnFiber(void delegate() cb, string file = __FILE__, int line = __LINE__)
void spawnFiber(string name, void delegate() cb, string file = __FILE__, int line = __LINE__)
{
spawnFiber(cb, defaultFiberPages, file, line);
spawnFiber(name, cb, defaultFiberPages, file, line);
}

void spawnFiber(void delegate() cb, int pages, string file = __FILE__, int line = __LINE__)
void spawnFiber(string name, void delegate() cb, int pages, string file = __FILE__, int line = __LINE__)
{
if (spawnFiberImpl)
spawnFiberImpl(cb, pages, file, line);
spawnFiberImpl(name, cb, pages, file, line);
else
setImmediate(cb);
}
Expand Down
125 changes: 94 additions & 31 deletions serverbase/source/served/utils/fibermanager.d
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module served.utils.fibermanager;
// debug = Fibers;

import core.thread;
import core.time;

import std.algorithm;
import std.experimental.logger;
Expand All @@ -14,23 +15,80 @@ public import core.thread : Fiber, Thread;

struct FiberManager
{
private Fiber[] fibers;
static struct FiberInfo
{
string name;
Fiber fiber;
MonoTime queueTime, startTime, endTime;
Duration timeSpent;
int numSteps = 0;
FiberManager* nested; /// for `joinAll` calls

alias fiber this;
}

static FiberManager* currentFiberManager;

ref FiberInfo currentFiber()
{
assert(currentFiberIndex != -1, "not inside a fiber in this FiberManager right now!");
return fibers[currentFiberIndex];
}

const(FiberInfo[]) fiberInfos() const
{
return fibers;
}

private size_t currentFiberIndex = -1;
private FiberInfo[] fibers;

FiberInfo[128] recentlyEnded;
size_t recentlyEndedIndex;

void call()
{
auto previousFiberManager = currentFiberManager;
currentFiberManager = &this;
scope (exit)
currentFiberManager = previousFiberManager;

MonoTime now;
size_t[] toRemove;
foreach (i, fiber; fibers)
foreach (i, ref fiber; fibers)
{
if (fiber.state == Fiber.State.TERM)
toRemove ~= i;
else
{
currentFiberIndex = i;
scope (exit)
currentFiberIndex = -1;
now = MonoTime.currTime;
if (fiber.numSteps == 0)
fiber.startTime = now;
fiber.call();
auto now2 = MonoTime.currTime;
fiber.numSteps++;
fiber.timeSpent += (now2 - now);
now = now2;
}
}

if (toRemove.length && now is MonoTime.init)
now = MonoTime.currTime;

foreach_reverse (i; toRemove)
{
debug (Fibers)
tracef("Releasing fiber %s", cast(void*) fibers[i]);
destroyUnset(fibers[i]);
auto rei = recentlyEndedIndex++;
if (recentlyEndedIndex >= recentlyEnded.length)
recentlyEndedIndex = 0;
if (recentlyEnded[rei] !is FiberInfo.init)
destroyUnset(recentlyEnded[rei].fiber);
move(fibers[i], recentlyEnded[rei]);
recentlyEnded[rei].endTime = now;
fibers = fibers.remove(i);
}
}
Expand All @@ -42,17 +100,11 @@ struct FiberManager

/// Makes a fiber call alongside other fibers with this manager. This transfers the full memory ownership to the manager.
/// Fibers should no longer be accessed when terminating.
void put(Fiber fiber, string file = __FILE__, int line = __LINE__)
void put(string name, Fiber fiber, string file = __FILE__, int line = __LINE__)
{
debug (Fibers)
tracef("Putting fiber %s in %s:%s", cast(void*) fiber, file, line);
fibers.assumeSafeAppend ~= fiber;
}

/// ditto
void opOpAssign(string op : "~")(Fiber fiber, string file = __FILE__, int line = __LINE__)
{
put(fiber, file, line);
fibers.assumeSafeAppend ~= FiberInfo(name, fiber, MonoTime.currTime);
}
}

Expand All @@ -67,58 +119,69 @@ private template hasInputRanges(Args...)
}

// ridiculously high fiber size (192 KiB per fiber to create), but for parsing big files this is needed to not segfault in libdparse
void joinAll(size_t fiberSize = 4096 * 48, Fibers...)(Fibers fibers)
void joinAll(size_t fiberSize = 4096 * 48, string caller = __FUNCTION__, Fibers...)(Fibers fibers)
{
import std.conv : to;

FiberManager f;
enum anyInputRanges = hasInputRanges!Fibers;
auto now = MonoTime.currTime;
static if (anyInputRanges)
{
Fiber[] converted;
FiberManager.FiberInfo[] converted;
converted.reserve(Fibers.length);
void addFiber(Fiber fiber)
void addFiber(string name, Fiber fiber)
{
converted ~= fiber;
converted ~= FiberManager.FiberInfo(name, fiber, now);
}
}
else
{
int i;
Fiber[Fibers.length] converted;
int convertedIndex;
FiberManager.FiberInfo[Fibers.length] converted;

void addFiber(Fiber fiber)
void addFiber(string name, Fiber fiber)
{
converted[i++] = fiber;
converted[convertedIndex++] = FiberManager.FiberInfo(name, fiber, now);
}
}

foreach (fiber; fibers)
{
static foreach (i, fiber; fibers)
{{
static immutable fiberName = caller ~ ".joinAll[" ~ i.stringof ~ "]";

static if (isInputRange!(typeof(fiber)))
{
foreach (fib; fiber)
foreach (j, fib; fiber)
{
string subName = fiberName ~ "[" ~ j.to!string ~ "]";
static if (is(typeof(fib) : Fiber))
addFiber(fib);
addFiber(subName, fib);
else static if (__traits(hasMember, fib, "toFiber"))
addFiber(fib.toFiber);
addFiber(subName, fib.toFiber);
else static if (__traits(hasMember, fib, "getYield"))
addFiber(new Fiber(&fib.getYield, fiberSize));
addFiber(subName, new Fiber(&fib.getYield, fiberSize));
else
addFiber(new Fiber(fib, fiberSize));
addFiber(subName, new Fiber(fib, fiberSize));
}
}
else
{
static if (is(typeof(fiber) : Fiber))
addFiber(fiber);
addFiber(fiberName, fiber);
else static if (__traits(hasMember, fiber, "toFiber"))
addFiber(fiber.toFiber);
addFiber(fiberName, fiber.toFiber);
else static if (__traits(hasMember, fiber, "getYield"))
addFiber(new Fiber(&fiber.getYield, fiberSize));
addFiber(fiberName, new Fiber(&fiber.getYield, fiberSize));
else
addFiber(new Fiber(fiber, fiberSize));
addFiber(fiberName, new Fiber(fiber, fiberSize));
}
}
}}

FiberManager.currentFiberManager.currentFiber.nested = &f;
scope (exit)
FiberManager.currentFiberManager.currentFiber.nested = null;

f.fibers = converted[];
while (f.length)
{
Expand Down
4 changes: 2 additions & 2 deletions source/served/commands/test_provider.d
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ void onDidAddProjectForUnittest(WorkspaceD.Instance instance, string dir, string
if (!doTrackTests)
return;

spawnFiber({
spawnFiber("Scan DUB project for unittests", {
if (!instance.has!DubComponent)
return;

Expand All @@ -58,7 +58,7 @@ void onDidSaveCheckForUnittest(DidSaveTextDocumentParams params)
if (!instance)
return;

spawnFiber({
spawnFiber("Run didSave processors", {
auto projectUri = workspace(params.textDocument.uri).folder.uri;

auto project = &projectTests.require(projectUri, UnittestProject(projectUri));
Expand Down
Loading

0 comments on commit 03100c1

Please sign in to comment.