Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
dmitry_sharshatkin
Product and Topic Expert
Product and Topic Expert
2,085

Case Description


I noticed that when Fiori Launchpad (FLP) is starting, it's calling /UI2/PAGE_BUILDER_PERS OData service via the URL like below:

/sap/opu/odata/UI2/PAGE_BUILDER_PERS/PageSets('%2FUI2%2FFiori2LaunchpadHome')?$expand=Pages/PageChipInstances/Chip/ChipBags/ChipProperties,Pages/PageChipInstances/RemoteCatalog,Pages/PageChipInstances/ChipInstanceBags/ChipInstanceProperties,AssignedPages,DefaultPage&sap-cache-id=6C0B84AA82291EDCA8F56801507C3C1B

This call is needed to get the needed information for your personal FLP configuration, including tiles, groups etc.

The result of this call is cached in your Internet Browser, however during the first login into FLP such call may take a very long time. It depends on the complexity of your FLP configuration.

But the performance of this call is also dependent on UI2 Cache (table /UI2/CACHE). You can disable cache in your Internet Browser and check the performance.

 

Performance Measurements


First, we delete entries in /UI2/CACHE for my user using the report /UI2/DELETE_CACHE.

After that we execute the sample URL in teh GW Client (/IWFND/GW_CLIENT).


GW Client - First Execution - 153 seconds


One can see it took around 153 seconds.

After that we can see that 332 entries have been created in the table /UI2/CACHE.


332 Cache Entries Added


After that we execute the ULR again and observe the performance is just about 15 seconds, or 10 times better than at initial call.


GW Client - Second Call - 15 seconds


 

Idea Realization


When a big number of new users or Big-Bang Go-Live is expected, it would be beneficial for end users and also from system capacity perspective to have the needed data pre-calculated and stored in UI2 Cache.

To do this, I have developed a report, which calls the needed URLs for the selected users.


Fill UI2 Cache Report


 

It will schedule a background job under the selected user’s name. The job will call the above URL, where the parameter sap-cache-id will be generated.


SM37 - Job Monitor


When job is finished the UI2 cache is filled, and the consequent executions of such query will take normal time.

At first login into Fiori Launchpad the data will be read from UI2 cache and will be cached on the client side.


HTTP Trace - First Call - 12 seconds


 

Afterwards, the data will be read from the browser cache.


HTTP Trace - Second Call - 0.5 Seconds


 

Coding


Below you can find the coding of the report.

Please do not treat it as SAP standard coding. It's just a template you can freely use for your needs and on your own responsibility. Obviously, no support is provided.
*&---------------------------------------------------------------------*
*& Report ZDMSH_UI2_CACHE_FILL
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
report zdmsh_ui2_cache_fill.

tables: usr02.

data: gv_url type string.

data: gr_dockingleft type ref to cl_gui_docking_container,
gr_text_editor type ref to cl_gui_textedit,
gv_repid type syrepid,
gt_textlines type table of tline-tdline.

select-options: so_usr for usr02-bname.
parameters: pa_usr type usr02-bname no-display.
parameters: pa_url type string no-display.
parameters: pa_btc type flag no-display default abap_false.

at selection-screen output.

gv_repid = sy-repid.

if sy-batch = abap_false and gr_dockingleft is not bound.

create object gr_dockingleft
exporting
repid = gv_repid
dynnr = sy-dynnr
side = gr_dockingleft->dock_at_left
extension = 1070.

create object gr_text_editor
exporting
parent = gr_dockingleft.

" Prepopulate with the longest request...
gt_textlines = value #( ( '/sap/opu/odata/UI2/PAGE_BUILDER_PERS/PageSets(''%2FUI2%2FFiori2LaunchpadHome'')?' )
( '$expand=Pages/PageChipInstances/Chip/ChipBags/ChipProperties,Pages/PageChipInstances/RemoteCatalog,' )
( 'Pages/PageChipInstances/ChipInstanceBags/ChipInstanceProperties,AssignedPages,DefaultPage' )
).

call method gr_text_editor->set_text_as_r3table
exporting
table = gt_textlines
exceptions
others = 1.
endif.

start-of-selection.

perform check_params.

perform get_base_url.

if pa_btc is initial.
perform start_process.
else.
perform call_url.
endif.



**********************************************************************************************
* Get Base URL
**********************************************************************************************
form check_params.
" Batch Mode...
if pa_btc is not initial.
if pa_url is initial.
message 'URL is not valid' type 'E'.
endif.
if pa_usr is initial.
message 'User ID is not specified' type 'E'.
endif.
endif.
endform.


**********************************************************************************************
* Get Base URL
**********************************************************************************************
form get_base_url.

if pa_url is not initial and pa_btc = abap_true.
gv_url = pa_url.
else.
if sy-batch = abap_false.
call method gr_text_editor->get_text_as_r3table
importing
table = gt_textlines
exceptions
others = 1.

clear: gv_url.
loop at gt_textlines into data(ls_text_line).
concatenate gv_url ls_text_line into gv_url.
endloop.
condense gv_url no-gaps.

" Remove SAP-CACHE-ID parameter...
split gv_url at '&' into table data(lt_url).
clear gv_url.
loop at lt_url into data(lv_url).
if not to_lower( lv_url ) cs 'sap-cache-id'.
concatenate gv_url lv_url into gv_url separated by '&'.
endif.
endloop.
shift gv_url left by 1 places in character mode.
endif.
endif.

if gv_url is initial.
message 'URL is not valid' type 'E'.
endif.
endform.


**********************************************************************************************
* Call URL {gv_url}
**********************************************************************************************
form call_url.

data: lo_client_proxy type ref to /iwfnd/cl_sutil_client_proxy.
data: lt_request_header type /iwfnd/sutil_property_t.

check: pa_btc is not initial.

lo_client_proxy = /iwfnd/cl_sutil_client_proxy=>get_instance( ).

" Set HTTP Method...
append value #( name = if_http_header_fields_sap=>request_method
value = 'GET' )
to lt_request_header[].

" Set Request URI...
append value #( name = if_http_header_fields_sap=>request_uri
value = gv_url )
to lt_request_header[].

message |Calling URL: { gv_url } | type 'S'.

call method lo_client_proxy->web_request(
exporting
it_request_header = lt_request_header
importing
ev_status_code = data(lv_status_code)
ev_status_text = data(lv_status_text)
ev_error_text = data(lv_error_text)
ev_error_timestamp = data(lv_error_timestamp)
ev_duration = data(lv_duration) ).

message |HTTP Code: { lv_status_code } | type 'S'.
message |Code Text: { lv_status_text } | type 'S'.
if lv_error_text is not initial.
message |Error: { lv_error_text } | type 'S'.
message |Error Timestamp: { lv_error_timestamp } | type 'S'.
endif.
message |Duration: { lv_duration } | type 'S'.

endform.


**********************************************************************************************
* Start Process
**********************************************************************************************
form start_process.

type-pools: sbtch.

data: lv_jobname type tbtcjob-jobname.
data: lv_jobcount type tbtcjob-jobcount.
data: ls_print_parameters type pri_params.
data: lv_url type string.
data: lv_max_proc type i.

check: pa_btc is initial.

" Get List of Users...
select distinct bname from usr02
into table @data(lt_usr)
where bname in @so_usr[].
if sy-subrc <> 0.
message 'No users selected' type 'E'.
endif.

call function 'TH_COUNT_WPS'
importing
btc_wps = lv_max_proc.
if lv_max_proc = 0.
lv_max_proc = 10.
endif.

loop at lt_usr into data(lv_usr).

clear: lv_jobname,
lv_jobcount,
ls_print_parameters,
lv_url.

lv_jobname = gv_repid && '_' && lv_usr-bname.

" Job open...
call function 'JOB_OPEN'
exporting
delanfrep = ' '
jobgroup = ' '
jobname = lv_jobname
sdlstrtdt = sy-datum
sdlstrttm = sy-uzeit
importing
jobcount = lv_jobcount
exceptions
cant_create_job = 01
invalid_job_data = 02
jobname_missing = 03.
if sy-subrc <> 0.
write: /, 'Did not start for ', lv_usr-bname.
continue.
endif.


" Set-up Print Parameteres...
call function 'GET_PRINT_PARAMETERS'
exporting
immediately = ' ' " leave blank so is not sent to print
no_dialog = 'X'
importing
out_parameters = ls_print_parameters
exceptions
archive_info_not_found = 1
invalid_print_params = 2
invalid_archive_params = 3
others = 4.
if sy-subrc <> 0.
write: /, 'Did not start for ', lv_usr-bname.
continue.
endif.

try.
lv_url = gv_url && '&sap-cache-id=' && cl_system_uuid=>if_system_uuid_static~create_uuid_c32( ).
catch cx_root.
exit.
endtry.

" Start Report for another user...
submit zdmsh_ui2_cache_fill to sap-spool and return
with pa_url = lv_url
with pa_usr = lv_usr-bname
with pa_btc = abap_true
user lv_usr-bname
spool parameters ls_print_parameters
without spool dynpro
via job lv_jobname
number lv_jobcount.

" Start Job...
call function 'JOB_CLOSE'
exporting
jobcount = lv_jobcount
jobname = lv_jobname
strtimmed = abap_true
exceptions
cant_start_immediate = 01
invalid_startdate = 02
jobname_missing = 03
job_close_failed = 04
job_nosteps = 05
job_notex = 06
lock_failed = 07
others = 99.
if sy-subrc <> 0.
write: /, 'Did not start for ', lv_usr-bname.
continue.
endif.

commit work.

" Check Job Count...
do 100 times.
select count(*) into @sy-dbcnt
from tbtcp where progname = @gv_repid
and sdldate = @sy-datum
and status in ( @sbtch_running, @sbtch_ready, @sbtch_scheduled, @sbtch_released ).
if sy-dbcnt ge lv_max_proc.
wait up to 10 seconds.
else.
exit.
endif.
enddo.

endloop.


endform.

 

Useful Links on the Topic


https://blogs.sap.com/2021/09/21/sap-fiori-for-sap-s-4hana-performance-optimization-and-best-practic...

 
2 Comments