Skip to content

Commit e123211

Browse files
committed
experimental memory usage cutters
1 parent 0f52d78 commit e123211

File tree

3 files changed

+62
-5
lines changed

3 files changed

+62
-5
lines changed

src/BuiltinExtensions/GridGenerator/GridGeneratorExtension.cs

+2
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ public static Font GetFont(float sizeMult)
400400

401401
public async Task<JObject> GridGenRun(WebSocket socket, Session session, JObject raw, string outputFolderName, bool doOverwrite, bool fastSkip, bool generatePage, bool publishGenMetadata, bool dryRun, bool weightOrder, string outputType, bool continueOnError, bool showOutputs)
402402
{
403+
Utilities.QuickGC();
403404
using Session.GenClaim claim = session.Claim(gens: 1);
404405
T2IParamInput baseParams;
405406
try
@@ -570,6 +571,7 @@ void DrawTextAutoScale(string text, float x, float y, float width, float height)
570571
Volatile.Write(ref data.ErrorOut, ExToError(ex));
571572
}
572573
}
574+
Utilities.QuickGC();
573575
if (grid is not null && grid.OutputType == Grid.OutputyTypeEnum.WEB_PAGE)
574576
{
575577
PostClean(session.User.OutputDirectory, outputFolderName);

src/Utils/Utilities.cs

+59-5
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,15 @@ public static void PrepUtils()
3838
int subticks = 0;
3939
Program.SlowTickEvent += () =>
4040
{
41-
GC.Collect(GC.MaxGeneration, GCCollectionMode.Optimized, false, false);
4241
if (subticks++ > 20)
4342
{
4443
subticks = 0;
4544
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, false, true);
4645
}
46+
else
47+
{
48+
QuickGC();
49+
}
4750
};
4851
new Thread(TickLoop).Start();
4952
}
@@ -253,7 +256,7 @@ public static CancellationTokenSource TimedCancel(TimeSpan time)
253256
public static async Task SendJson(this WebSocket socket, JObject obj, TimeSpan maxDuration)
254257
{
255258
using CancellationTokenSource cancel = TimedCancel(maxDuration);
256-
await socket.SendAsync(obj.ToString(Formatting.None).EncodeUTF8(), WebSocketMessageType.Text, true, cancel.Token);
259+
await socket.SendAsync(JsonToByteArray(obj), WebSocketMessageType.Text, true, cancel.Token);
257260
}
258261

259262
/// <summary>Equivalent to <see cref="Task.WhenAny(IEnumerable{Task})"/> but doesn't break on an empty list.</summary>
@@ -378,6 +381,52 @@ public static JObject SortByKey<TSortable>(this JObject obj, Func<string, TSorta
378381
return JObject.FromObject(obj.Properties().OrderBy(p => sort(p.Name)).ToDictionary(p => p.Name, p => p.Value));
379382
}
380383

384+
/// <summary>(Experimental) aggressively simply low-mem ToString for JSON data. Dense, spaceless, unformatted.</summary>
385+
public static void ToStringFast(this JToken jval, StringBuilder builder)
386+
{
387+
if (jval is JObject jobj)
388+
{
389+
builder.Append('{');
390+
if (jobj.Count > 0)
391+
{
392+
foreach ((string key, JToken val) in jobj)
393+
{
394+
builder.Append('"').Append(EscapeJsonString(key)).Append("\":");
395+
val.ToStringFast(builder);
396+
builder.Append(',');
397+
}
398+
builder.Length--;
399+
}
400+
builder.Append('}');
401+
}
402+
else if (jval is JArray jarr)
403+
{
404+
builder.Append('[');
405+
if (jarr.Count > 0)
406+
{
407+
foreach (JToken val in jarr)
408+
{
409+
val.ToStringFast(builder);
410+
builder.Append(',');
411+
}
412+
builder.Length--;
413+
}
414+
builder.Append(']');
415+
}
416+
else
417+
{
418+
builder.Append(jval.ToString(Formatting.None));
419+
}
420+
}
421+
422+
/// <summary>Converts a <see cref="JObject"/> to a UTF-8 string byte array.</summary>
423+
public static byte[] JsonToByteArray(JObject jdata)
424+
{
425+
StringBuilder builder = new(1024);
426+
jdata.ToStringFast(builder);
427+
return builder.ToString().EncodeUTF8();
428+
}
429+
381430
/// <summary>Gives a clean standard 4-space serialize of this <see cref="JObject"/>.</summary>
382431
public static string SerializeClean(this JObject jobj)
383432
{
@@ -391,7 +440,6 @@ public static string SerializeClean(this JObject jobj)
391440
serializer.Serialize(jw, jobj);
392441
jw.Flush();
393442
return sw.ToString() + Environment.NewLine;
394-
395443
}
396444

397445
public static async Task YieldJsonOutput(this HttpContext context, WebSocket socket, int status, JObject obj)
@@ -403,7 +451,7 @@ public static async Task YieldJsonOutput(this HttpContext context, WebSocket soc
403451
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, cancel.Token);
404452
return;
405453
}
406-
byte[] resp = obj.ToString(Formatting.None).EncodeUTF8();
454+
byte[] resp = JsonToByteArray(obj);
407455
context.Response.ContentType = "application/json";
408456
context.Response.StatusCode = status;
409457
context.Response.ContentLength = resp.Length;
@@ -419,7 +467,7 @@ public static JObject ErrorObj(string message, string error_id)
419467

420468
public static ByteArrayContent JSONContent(JObject jobj)
421469
{
422-
ByteArrayContent content = new(jobj.ToString(Formatting.None).EncodeUTF8());
470+
ByteArrayContent content = new(JsonToByteArray(jobj));
423471
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
424472
return content;
425473
}
@@ -971,6 +1019,12 @@ public static string GetLocalIPAddress()
9711019
return null;
9721020
}
9731021

1022+
/// <summary>Encourage the Garbage Collector to clean up memory.</summary>
1023+
public static void QuickGC()
1024+
{
1025+
GC.Collect(GC.MaxGeneration, GCCollectionMode.Optimized, false, false);
1026+
}
1027+
9741028
/// <summary>Cause an immediate aggressive RAM cleanup.</summary>
9751029
public static void CleanRAM()
9761030
{

src/WebAPI/ModelsAPI.cs

+1
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ bool tryMatch(string name)
254254
{
255255
files.Reverse();
256256
}
257+
Utilities.QuickGC(); // (Could potentially be quite large data, so encourage GC to not slam RAM from listing out model data)
257258
return new JObject()
258259
{
259260
["folders"] = JArray.FromObject(folders.ToList()),

0 commit comments

Comments
 (0)