A project library script runs on the Ignition Gateway, but its CPU and execution-time impact is unclear. Follow the request from its trigger through the calling script, the Stale library function, and any downstream work. A project library function is reusable code, not an independent scheduled task, so its execution context and diagnostic visibility come from whatever calls it.
Which execution path calls the project library?
Identify the sender before measuring the function. The request may begin in a gateway event script, a timer script, or another script that calls the project library. The caller determines when execution starts, how often it runs, whether calls can overlap, and which Gateway diagnostic counters can expose it.
| Path element | Question to answer | Useful observation |
|---|---|---|
| Trigger | What starts the request? | Record the gateway event or timer script that invokes the library. |
| Caller | Where is Stale called? |
Count every call site, including calls made inside loops or recursive paths. |
| Library function | What work happens inside the timed boundary? | Separate imports, computation, logging, and calls to other resources. |
| Return path | When is the request complete? | Measure until the function returns or raises an error. |
A short function can still create load if the caller invokes it frequently or concurrently. Conversely, a long execution can spend most of its time waiting rather than consuming CPU. Record both execution time and Gateway CPU so the two effects are not confused.
Check: Trace one invocation from its trigger to the return from Stale, and identify every place where another invocation can begin.
Is the Gateway healthy before the script runs?
Open the Gateway web portal and go to the Diagnostics overview. Observe Gateway CPU usage before starting the test. This baseline distinguishes an existing Gateway-wide load from a change associated with the script.
Layer one first: confirm that the Gateway host remains responsive and that the test is not beginning during an unrelated CPU spike. CPU is a shared measurement; it does not attribute consumption to one project library function. Treat it as the system-level side of a paired test, with function duration providing the code-level side.
| Measurement | Before test | During test | Interpretation |
|---|---|---|---|
| Gateway CPU | Capture the normal baseline | Observe while controlled calls execute | A repeatable rise indicates system load correlated with the test, but not necessarily CPU consumed only by Stale. |
| Function duration | No call active | Time each complete call | Shows latency for the selected code boundary. |
| Call count | Record the starting count | Count completed calls | Prevents a frequency change from being mistaken for a per-call regression. |
Use the same test input and invocation pattern for each comparison. Changing the workload and the code simultaneously makes the CPU comparison inconclusive.
Check: Capture a stable CPU baseline and a defined call count before enabling detailed timing.
What can the Scripts diagnostic view prove?
In the Gateway Diagnostics area, open the Scripts tab. Use it to inspect additional information about running scripts and the execution statistics exposed for gateway event scripts, including timer scripts. This view helps locate scripts that are active, delayed, or repeatedly invoked.
The project library entry does not create its own scheduling context. If Stale is called by a gateway timer event, start with that timer's statistics, then instrument the library call to isolate its contribution. If the caller performs other work before or after the function, the caller's total execution time will be greater than the library measurement.
| Observed scope | What it measures | What it cannot isolate |
|---|---|---|
| Diagnostics overview | Gateway-level CPU usage | Time consumed by one function |
| Scripts diagnostics | Displayed activity and execution statistics for applicable scripts | A nested project library call unless its boundary is separately timed |
| Instrumented function | Elapsed time between entry and exit | Gateway-wide impact without the CPU and call-frequency measurements |
Check: Match the visible gateway event or timer entry to the caller found in the first step.
How should the function boundary be timed?
Use Java's System.nanoTime() for elapsed-time measurement in Jython. It supplies a monotonic, cross-CPU-synchronized nanosecond clock intended for performance tracking. Measure a difference between two readings; do not treat either reading as a wall-clock timestamp.
from java.lang import System
logger = system.util.getLogger("Stale")
def measure(callableObject):
start = System.nanoTime()
try:
return callableObject()
finally:
elapsed = System.nanoTime() - start
logger.info("Stale elapsed ns: %d" % elapsed)
Place the start immediately before the call being evaluated. The finally block records elapsed time even when the call raises an exception. Keep the measurement boundary unchanged between tests. If recursive calls are timed individually as well as through the outer call, the resulting durations overlap and must not be added together.
Use system.util.getLogger to send measurements to a named logger. During performance testing, control the number of log messages: logging every iteration can become part of the measured workload. For a frequent script, collect a representative series rather than judging the function from one run. Compare the distribution and worst recurring values, not only the fastest result.
Check: Confirm that each controlled invocation produces one outer elapsed-time record and that exceptions still produce a duration.
Which import pattern adds avoidable work?
Move stable library imports to module scope instead of executing import statements inside a frequently called function. Imported modules are normally cached, but the import statement still performs lookup and binding work on every function invocation. Repeated calls, recursion, and short timer periods multiply that overhead.
Do not import Ignition's system scripting library inside the function; it is provided by the Ignition scripting environment. Java's System class is different. Import java.lang.System at module scope when using System.nanoTime().
One measured recursive project function took 250 ms with five imports inside the function and 40 ms after those imports were removed from the function, a reduction of 210 ms for that test case. Treat those values as a measured comparison, not a universal import cost; repeat the before-and-after timing on the actual Stale call path.
| Setting or pattern | Effect | Action |
|---|---|---|
| Imports inside a hot function | Repeats import lookup and binding during calls | Move stable imports to module scope. |
import system |
Adds an unnecessary import for the Ignition scripting library | Use the supplied system object directly. |
from java.lang import System |
Makes the Java timing class available | Place it at module scope. |
Check: Run the same inputs and call count before and after moving imports, then compare elapsed time and Gateway CPU.
How is the complete path verified?
- Record the idle Gateway CPU baseline from the Diagnostics overview.
- Confirm the gateway event or timer caller in the Scripts diagnostic view.
- Execute a controlled number of calls with unchanged inputs.
- Record outer-call durations using
System.nanoTime()and theStalelogger. - Repeat the test after moving function-local imports to module scope.
- Compare call count, elapsed-time records, caller statistics, and Gateway CPU for the same test interval.
A valid result requires agreement across the path: the expected caller fires, the expected number of timing records appears, each call completes, and the Gateway returns to its prior CPU baseline after the workload stops.
FAQ
Why does my Ignition project library script not appear as a separate timer?
A project library function is called code, not an independent schedule. Inspect the gateway event or timer script that calls Stale, then time the nested function boundary separately.
Why does a short script still affect Gateway performance?
Call frequency, overlapping invocations, recursion, and repeated imports can multiply a small per-call cost. Compare elapsed time, call count, caller statistics, and Gateway CPU during the same controlled interval.
Why use System.nanoTime instead of a normal timestamp?
System.nanoTime() is designed for elapsed-time performance tracking and is cross-CPU synchronized. Subtract the start reading from the finish reading; do not interpret the values as calendar time.
How do I prove an Ignition script change reduced Gateway load?
Repeat the same input and call count, confirm one timing record per outer call, compare the before-and-after durations and CPU observations, and verify that the expected caller completes and the Gateway returns to its baseline after the final test.