A Brief History of Performance

A Brief History of Performance

The question I want to look here is how to speed up my automation workflows in the context of SAP. Often there is the situation that there must be processed a lot amount of data, but the time to do that is not enough. So first I focused on the question how fast I am. For this I made a direct comparison between the use of SAP GUI Scripting via Windows Scripting Host and a UiPath workflow.

At first the VBScript code:

StartTime = Timer
For i = 1 To 10
  session.findById("wnd[0]/tbar[0]/okcd").text = "/nSE16"
  session.findById("wnd[0]").sendVKey 0
  session.findById("wnd[0]/usr/ctxtDATABROWSE-TABLENAME").text = "TADIR"
  session.findById("wnd[0]").sendVKey 0
  session.findById("wnd[0]").sendVKey 31
  session.findById("wnd[1]/tbar[0]/btn[0]").press
Next
EndTime = Timer
TimeIt = EndTime – StartTime
MsgBox CStr(TimeIt)

Now the corresponding workflow:

The differences are considerable. The VBScript code needs approx. 17 seconds and the UiPath workflow needs approx. 48 seconds. VBScript code is nearly three times faster. Now I combine these solutions to the following workflow:

Now the UiPath workflow needs approx. 18 seconds. Great.

Then I thought about what this integration scenario actually means.

Advantages and Disadvantages

The advantages of the solution above can be bundled in one word: Speed. The disadvantages contain a few perspectives. The most concise is the loss of control over a part of the process. One step of your automation workflow is now a black box, which contains a lot of steps. These steps escape the visibility of the workflow and therefore the understanding of a person who works with it. It works outside, on a different (language) platform. This also requires more knowledge at other levels, e.g. programming. In the case of an error it must be ensured that there is seamless communication with the calling workflow, to provide it with clear error messages. This integration requirement increases the effort of the workflow building.

Conclusion

Speed does not justify the loss of many advantages that RPA offers us. The scalability of bots offers us the possibility to compensate limited time frames. With complex consolidated solutions this integration scenarios can be considered, or where it is not otherwise possible. In any other case an RPA implementation should be preferred. Speed is not everything. It is our job to build RPA processes so that they are efficient.

3 Likes

Excellent post @StefanSchnell. So many of us are targeting transactional solutions for client systems. It is vital to properly frame the unique value that RPA brings to the table. We do have to answer the speed question but value looms much larger.

1 Like

Thank you @jamiejam :slightly_smiling_face:

SAP Intelligent RPA - A Look Over the Fence

In retrospect I was interested how other RPA platforms behave. To look at this, I implemented the same approach with SAP Intelligent RPA. Here the workflow from Desktop Studio:

Here the JavaScript code:

// ----------------------------------------------------------------
//   Test menu for scenario newWorkflow 
// ----------------------------------------------------------------
GLOBAL.events.START.on(function (ev) {
	if (ctx.options.isDebug) {
		// Add item in systray menu.
		systray.addMenu('', 'newWorkflow', 'Test newWorkflow', '', function (ev) {
			var rootData = ctx.dataManagers.rootData.create();
			
			// Initialize your data here.
			SAPEasyAccess.scenarios.newWorkflow.start(rootData);
		});
	}
});

//---------------------------------------------------
// Scenario newWorkflow Starter ()
//---------------------------------------------------

// ----------------------------------------------------------------
//   Scenario: newWorkflow
// ----------------------------------------------------------------
SAPEasyAccess.scenario({ newWorkflow: function(ev, sc) {
	var rootData = sc.data;

	sc.setMode(e.scenario.mode.clearIfRunning);
	sc.setScenarioTimeout(600000); // Default timeout for global scenario.
	sc.onError(function(sc, st, ex) { sc.endScenario(); }); // Default error handler.
	sc.onTimeout(30000, function(sc, st) { sc.endScenario(); }); // Default timeout handler for each step.
	// Initialize Loop counters
	sc.localData.Startloop = 0;

	rootData.start = new Date().getTime();
	
	
	sc.step(SAPEasyAccess.steps.Start_loop, SAPEasyAccess.steps.pSAPEasyAccess_manage);
	sc.step(SAPEasyAccess.steps.pSAPEasyAccess_manage, SAPEasyAccess.steps.Loops_to_the_start_bl, 'NEXT_LOOP');
	sc.step(SAPEasyAccess.steps.pSAPEasyAccess_manage, SAPEasyAccess.steps.pDataBrowserInitial_m);
	sc.step(SAPEasyAccess.steps.pDataBrowserInitial_m, SAPEasyAccess.steps.Loops_to_the_start_bl, 'NEXT_LOOP');
	sc.step(SAPEasyAccess.steps.pDataBrowserInitial_m, SAPEasyAccess.steps.pDataBrowserTableT_ma);
	sc.step(SAPEasyAccess.steps.pDataBrowserTableT_ma, SAPEasyAccess.steps.Loops_to_the_start_bl, 'NEXT_LOOP');
	sc.step(SAPEasyAccess.steps.pDataBrowserTableT_ma, SAPEasyAccess.steps.pDisplayNumberOfEnt_m);
	sc.step(SAPEasyAccess.steps.pDisplayNumberOfEnt_m, SAPEasyAccess.steps.Loops_to_the_start_bl, 'NEXT_LOOP');
	sc.step(SAPEasyAccess.steps.pDisplayNumberOfEnt_m, SAPEasyAccess.steps.pDataBrowserTableT_ma_1);
	sc.step(SAPEasyAccess.steps.pDataBrowserTableT_ma_1, SAPEasyAccess.steps.Loops_to_the_start_bl, 'NEXT_LOOP');
	sc.step(SAPEasyAccess.steps.pDataBrowserTableT_ma_1, SAPEasyAccess.steps.Exit_loop);
	sc.step(SAPEasyAccess.steps.Exit_loop, SAPEasyAccess.steps.Loops_to_the_start_bl, 'NEXT_LOOP');
	sc.step(SAPEasyAccess.steps.Exit_loop, SAPEasyAccess.steps.Loops_to_the_start_bl);
	sc.step(SAPEasyAccess.steps.Loops_to_the_start_bl, SAPEasyAccess.steps.Start_loop, 'NEXT_LOOP');
	
}}, ctx.dataManagers.rootData).setId('b1d7dbae-8a8d-4f78-854d-e9fad301e91a') ;

// ----------------------------------------------------------------
//   Step: Start_loop
// ----------------------------------------------------------------
SAPEasyAccess.step({ Start_loop: function(ev, sc, st) {
	var rootData = sc.data;
	
	ctx.workflow('newWorkflow', 'b96c70f2-8bf1-43f4-ac5d-a2e78b763a78') ;
	// Starting instruction for a loop.
	if (sc.localData.Startloop < 0) sc.localData.Startloop = 0;
	sc.endStep(); // pSAPEasyAccess_manage
	return;
}});

// ----------------------------------------------------------------
//   Step: pSAPEasyAccess_manage
// ----------------------------------------------------------------
SAPEasyAccess.step({ pSAPEasyAccess_manage: function(ev, sc, st) {
	var rootData = sc.data;
	ctx.workflow('newWorkflow', 'e6f8fac0-109b-41c9-9f95-098ee0311125') ;
	// Wait until the Page loads
	SAPEasyAccess.pSAPEasyAccess.wait(function(ev) {
		SAPEasyAccess.pSAPEasyAccess.oGuiOkCodeField.set("/nSE16");
		// Sends a key sequence to a page.
		SAPEasyAccess.pSAPEasyAccess.keyStroke(e.SAPScripting.key._Enter_);
		sc.endStep(); // pDataBrowserInitial_m
		return;
	});
}});

// ----------------------------------------------------------------
//   Step: pDataBrowserInitial_m
// ----------------------------------------------------------------
SAPEasyAccess.step({ pDataBrowserInitial_m: function(ev, sc, st) {
	var rootData = sc.data;
	ctx.workflow('newWorkflow', '7090b4f7-e9e2-4480-a339-35e23679c167') ;
	// Wait until the Page loads
	SAPEasyAccess.pDataBrowserInitial.wait(function(ev) {
		SAPEasyAccess.pDataBrowserInitial.edTableName.set("TADIR");
		// Sends a key sequence to a page.
		SAPEasyAccess.pDataBrowserInitial.keyStroke(e.SAPScripting.key._Enter_);
		sc.endStep(); // pDataBrowserTableT_ma
		return;
	});
}});

// ----------------------------------------------------------------
//   Step: pDataBrowserTableT_ma
// ----------------------------------------------------------------
SAPEasyAccess.step({ pDataBrowserTableT_ma: function(ev, sc, st) {
	var rootData = sc.data;
	ctx.workflow('newWorkflow', 'dc4471f3-7c97-4354-8eea-4eeec545743e') ;
	// Wait until the Page loads
	SAPEasyAccess.pDataBrowserTableT.wait(function(ev) {
		// Sends a key sequence to a page.
		SAPEasyAccess.pDataBrowserTableT.keyStroke(e.SAPScripting.key._Ctrl__F7_);
		sc.endStep(); // pDisplayNumberOfEnt_m
		return;
	});
}});

// ----------------------------------------------------------------
//   Step: pDisplayNumberOfEnt_m
// ----------------------------------------------------------------
SAPEasyAccess.step({ pDisplayNumberOfEnt_m: function(ev, sc, st) {
	var rootData = sc.data;
	ctx.workflow('newWorkflow', '7061e35c-014c-4d61-8b84-600c2be1c4fc') ;
	// Wait until the Page loads
	SAPEasyAccess.pDisplayNumberOfEnt.wait(function(ev) {
		SAPEasyAccess.pDisplayNumberOfEnt.btClose.click();
		sc.endStep(); // pDataBrowserTableT_ma_1
		return;
	});
}});

// ----------------------------------------------------------------
//   Step: pDataBrowserTableT_ma_1
// ----------------------------------------------------------------
SAPEasyAccess.step({ pDataBrowserTableT_ma_1: function(ev, sc, st) {
	var rootData = sc.data;
	ctx.workflow('newWorkflow', '2c1d8ace-1c6e-4912-bfeb-45c48232bd4f') ;
	// Wait until the Page loads
	SAPEasyAccess.pDataBrowserTableT.wait(function(ev) {
		SAPEasyAccess.pDataBrowserTableT.oGuiOkCodeField.set("/n");
		// Sends a key sequence to a page.
		SAPEasyAccess.pDataBrowserTableT.keyStroke(e.SAPScripting.key._Enter_);
		sc.endStep(); // Exit_loop
		return;
	});
}});

// ----------------------------------------------------------------
//   Step: Exit_loop
// ----------------------------------------------------------------
SAPEasyAccess.step({ Exit_loop: function(ev, sc, st) {
	var rootData = sc.data;
	
	ctx.workflow('newWorkflow', '84a226e6-120e-4fc7-aace-124046a26559') ;
	// Test block to exit from a loop.
	if (sc.localData.Startloop > 9)
	{
		sc.localData.Startloop = -1 ;
		sc.endStep('NEXT_LOOP');
		return ;
	}
	sc.endStep(); // Loops_to_the_start_bl
	return;
}});

// ----------------------------------------------------------------
//   Step: Loops_to_the_start_bl
// ----------------------------------------------------------------
SAPEasyAccess.step({ Loops_to_the_start_bl: function(ev, sc, st) {
	var rootData = sc.data;
	
	ctx.workflow('newWorkflow', 'fc061908-fc2b-4a45-aaeb-9b2347ba9447') ;
	// Loops to the start block.
	if (sc.localData.Startloop != -1)
	{
		sc.localData.Startloop++ ;
		sc.endStep('NEXT_LOOP');
		return ;
	}
	sc.endStep(); // end Scenario
	var end = new Date().getTime();
	var time = end - rootData.start;
	ctx.log(time.toString());
	return;
}});

And here the result from the Desktop Debugger:

image

Approx. 48 seconds. This perspective confirmed the conclusion from above and there is nothing to add.

1 Like