JSReport local performance



  • I have been using JSReport to convert the html to pdf with Phantom PDF recipe and jsreport.local and jsreport.binary packages.

    I have noticed that it takes almost 3 seconds once warmed up to complete the conversion. Can you please suggest some improvement that I can do to improve its performance to ms?



  • Hi, we are tracking related issue for improving performance here.
    Until that is implemented, you can initialize jsreprot as web server.

    https://jsreport.net/learn/dotnet-local#utility-or-web-server

    var rs = new LocalReporting().UseBinary(JsReportBinary.GetStream()).AsWebServer().Create();
    await rs.StartAsync();
    
    var report = await rs.RenderAsync(...);
    
    await rs.KillAsync();
    


  • Hmmmmm....I can't seem to find JSReportBinary.GetStream() method in jsreport dlls.



  • Ah ok, need to fix this in the docs. Please use JsReportBinary.GetBinary(). Thank you for notice.



  • Thanks for your quick response but I see better performance with Binary then web server in my case!



  • Even for the second run?



  • Yes first run ~7secs, second run ~2 seconds same as binary in my case....and even I am not killing the process. If I kill then ~7-8 seconds every request.



  • Ok. You have some kind of complex html I guess right? In this case switching to web server doesn't help so much. It is significant for the small reports.
    Can you paste here debug logs? Get it this way:

    var logs = "";
    long startTime = invoiceReport.Meta.Logs.First().Timestamp.Ticks;
    foreach (var l in invoiceReport.Meta.Logs)
    {               
        logs += $"+{Math.Round((double)(l.Timestamp.Ticks - startTime)/1000)} {l.Message}\n";
    }    
    


  • Well it is not that complex a very simple template. The thing is I am using DI to inject the instance and can't exactly measure time as you suggested. I will still give it a go and share the logs.



  • Here is a sample log output: (I am not killing rs.KillAsync() and kept it running and see an improvement).

    +0 Starting rendering request 3
    +0 Rendering anonymous template { recipe:phantom-pdf,engine:handlebars}
    +10 Inline data specified.
    +30 Resources not defined for this template.
    +40 Base url not specified, skipping its injection.
    +40 Rendering engine handlebars
    +110 Taking compiled template from engine cache
    +150 Replaced images []
    +160 Executing recipe phantom-pdf
    +7040 Converting in dedicated phantomjs 1.9.8
    +7090 Request file:///C%3A%5CUsers%5Cparmars%5CAppData%5CLocal%5CTemp%5Cjsreport-temp%5Cdb27c960-c8d0-11e7-9b09-114472c202cehtml.html
    +7130 Request data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAA...
    +7140 Request data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQECA...
    +7820 phantom-pdf recipe finished with 1 pages generated
    +7830 Skipping storing report.
    +7850 Rendering request finished 3

    +0 Starting rendering request 4
    +0 Rendering anonymous template { recipe:phantom-pdf,engine:handlebars}
    +10 Inline data specified.
    +40 Resources not defined for this template.
    +40 Base url not specified, skipping its injection.
    +40 Rendering engine handlebars
    +80 Taking compiled template from engine cache
    +120 Replaced images []
    +130 Executing recipe phantom-pdf
    +7280 Converting in dedicated phantomjs 1.9.8
    +7320 Request file:///C%3A%5CUsers%5Cparmars%5CAppData%5CLocal%5CTemp%5Cjsreport-temp%5Cf64be050-c8d0-11e7-9b09-114472c202cehtm
    +7390 Request data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAA...
    +7400 Request data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQECA...
    +8330 phantom-pdf recipe finished with 1 pages generated
    +8330 Skipping storing report.
    +8350 Rendering request finished 4



  • Thank you. I see in logs that it spends the most of the time in phantomjs which is rendering the pdf. That is something we cannot influence.
    However could you share the html input file?

    It should be available during the rendering in the temp
    +7320 Request file:///C%3A%5CUsers%5Cparmars%5CAppData%5CLocal%5CTemp%5Cjsreport-temp%5Cf64be050-c8d0-11e7-9b09-114472c202cehtm

    If there are some sensitive information, feel free to send me a direct email.



  • email sent with attachment for your review.



  • Thank you. I will look into it.



  • I get 700ms if running this code with provided html

    var rs = new LocalReporting()
                    .KillRunningJsReportProcesses()
                    .UseBinary(JsReportBinary.GetBinary())
                    .AsWebServer()
                    .Create();
    await rs.StartAsync();
    
    var testingContent = File.ReadAllText("test.html");
    
    Func<Task<Report>> render = () => rs.RenderAsync(new RenderRequest()
    {
        Template = new Template()
        {
            Content = testingContent,
            Engine = Engine.None,
            Recipe = Recipe.PhantomPdf
        }
    });
    
    //warm up
    await render();
    //messure second
    var now = DateTime.Now;
    await render();
    var totalMs = (DateTime.Now - now).TotalMilliseconds;
    Console.WriteLine(totalMs);
    
    await rs.KillAsync();
    

    We could get to like 300ms if we add support for reusing phantomjs instances over requests. This is already supported in the full jsreport. It is just missing in the compiled binary used in jsreport.Local. I've submitted improvement request to which you can subscribe here.

    If the 700ms is an issue for you and you need to solve it right now, you can always startup full jsreport or use jsreportonline and connect to it using jsreport c# client. Both support reusing phantomjs instances.



  • Thanks Jan! I was able to bring down performance also by using the web server to an acceptable level. You guys are just amazing and community is brilliant at posting quick reply. I am so happy that I choose JSReport for our reporting problems!



  • Great! Thank you. Glad to be helpful.



  • Hi Jan, is there a github issue to subscribe to for the UseBinary performance relative to AsWebServer? We are going to be deploying a single report with that approach soon, but will ultimately be purchasing and running 20-30 reports by spring time. So, we are curious on timing, or if it would make more sense to use a standalone server at that point. Thanks!



  • @dmTech04 Here is the optimization issue. Running standalone jsreport instance is usually better in architectural and scale aspect, but the jsreport.Local is on the other hand more convenient....



  • Thanks @jan_blaha. I am coming to the same realization. :)


Log in to reply
 

Looks like your connection to jsreport forum was lost, please wait while we try to reconnect.