Update
I figured that I can make the code much faster (close to the speed without any Echo) if I can get rid of all the if's and let the pattern matcher(which is pretty fast) do all the heavy work for me.
BeginPackage["MyEcho`"];
MaxEchoCount=5;
MyEcho::stop="Max Echo count of reached, further will be suppressed during evaluation of In[``].";
SetAttributes[MyEcho,HoldAllComplete]
Module[{list={}},
MyEcho[label_,return_,subexpr___]:=
Which[
list[[label]]<MyEchoMaxEchoCount,list[[label]]++;Echo[return,subexpr], list[[label]]==MyEchoMaxEchoCount,Message[MyEcho::stop,MyEcho`MaxEchoCount,Defer[Echo[return,subexpr]],$Line];MyEcho[label,return1_,subexpr1___]:=return1;return];
$Pre=Function[{expr},
Quiet@Cases[DownValues[MyEcho],HoldPattern[MyEcho[label_Integer,e___]]:>Unset[MyEcho[label,e]],Infinity];
list=ConstantArray[0,Length@list];
ReleaseHold[Hold[expr]/. HoldPattern[Echo[subexpr__]]:>With[{c=(AppendTo[list,0];Length@list)},MyEcho[c,subexpr]/;True]],HoldAll];
];
EndPackage[];
The key here is that I will add a narrower definition to MyEcho once it reached the maximum echo count, so the next time it meets the same function at the same place, it will hit the new function definition and directly return.
One can compare this version to the old version, as well as the version with QuietEcho wrapped around the whole expression with the following code:
Table[Flatten[{{Table[Echo[x], 2], Echo[10 - x]}, {Sqrt[2]}}], {x, 1000000}]
The results are:
- Without
Echo: 1.84s
- With
QuietEcho wrapped around everything: 2.76s
- With the new definition: 2.42s
- With the old definition: 5.61s
Old version
crit = 2;
SetAttributes[MyEcho, HoldAll]
Module[{res},MyEcho[label_, return_, subexpr___] :=
If[NumberQ[label],If[label >= crit, return,
label++; res = Echo[return, subexpr];
If[label == crit, Print["Already " <> ToString[crit] <> " Echo here!\nNo more Echo allowed!!!!"]];res],
label = 1; Echo[return, subexpr]]]
$Pre =
Function[{expr}, ReleaseHold[Hold[expr] /. HoldPattern[Echo[subexpr__]] :>
With[{u = Unique[]}, MyEcho[u, subexpr] /; True]], HoldAll]
Similar results, but a bit more integrated and more carefully protected.

Note that one can still save the old $Pre by adding it in front of this code.(one must limit the functionality of old $Pre to an extent that full evaluation of expressions is forbidden)
EchonamedLimitEcho: https://resources.wolframcloud.com/FunctionRepository/resources/LimitEcho/ – userrandrand Dec 12 '22 at 20:11ResourceFunction["LimitEcho"][ImageApply[Echo[#]&,ExampleData[{"TestImage","Lena"}]],5]– yode Dec 13 '22 at 03:15c = 0; ImageApply[If[c < 5, c++; Echo[#], #] &, ExampleData[{"TestImage", "Lena"}]]? That could be tedious to reset c=0 each time we need it for a new code. – userrandrand Dec 13 '22 at 17:01