Muhammad-Sharif Moustafa on Wed, 20 Dec 2017 23:52:08 +0100 |
[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]
Re: Working on iOS port |
> On Dec 19, 2017, at 5:47 AM, Bill Allombert <Bill.Allombert@math.u-bordeaux.fr> wrote: > > On Tue, Dec 19, 2017 at 12:40:15AM -0500, ProtonMail wrote: >> >>> On Dec 18, 2017, at 11:39 AM, Bill Allombert <Bill.Allombert@math.u-bordeaux.fr> wrote: >> I’ve actually seen that link before in the Google rabbit hole I went >> down when I was trying to compile pari for iOS. I haven’t gotten >> around to trying the method outlined in that article yet, but I plan >> on doing it. What confuses me though is that you’ll end up with an >> executable after building pari with the custom build script at the top >> of the article. If my assumption is correct, how would you get that >> executable on the device without jailbreaking it to gain access to the >> file system? Is it possible to bundle the executable with an iOS app >> so that the app can interface with the executable? I know that it is >> possible to include a static library on iOS, but I was having trouble >> compiling libpari.a for arm64. I wasn’t aware of the cross-compiler >> though, so I’ll use the info from that webpage as a starting point to >> produce an arm64 version of libpari.a and go from there. > > I have no idea. I assume to use the raw binary you need to jailbreak > your phone. You might be able to package it in a app, but then Apple > will not approve it because it is licensed under the GNU GPL. Oh, I did not realize that GPL was incompatible with Apple’s App Store. After doing some reading about it, that does seem to be the case. If the ownership of and copyright to this app was given to the Pari project, would the issue still remain? Since Pari would have control over the app, would it be possible to release the app under a different license for the purpose of distributing the app on the app store? If not, then we could continue with the development of the app as is, and simply direct people to compile the app on their own computers and load it on their devices manually. That’s probably an issue for computer novices though and it would require that they had a Mac to do that. In addition to an iOS app, what if we were to make a mobile-optimized progressive web app of Pari? It would essentially work like the current GP browser implementation but it would have the features of a progressive web app, such as offline caching of webpage scripts and being able to add it to the home screen on Android and iOS devices. This would have the feel of an app but without going through restrictive app stores. Rather, the web app would be served from the pari.math.u-bordeaux.fr server. I have experience with web apps, so I could work on this. This website offers a good explanation: https://developers.google.com/web/progressive-web-apps/. What do you think? > >>> Indeed! Do you know whether JavaScriptCore support WebAssembly ? >> >> It does! But only on iOS 11 and up, according to https://caniuse.com/#feat=wasm. >> >>> >>> How does your app compares to >>> <https://pari.math.u-bordeaux.fr/gp.html> ? >> >> Unfortunately, that webpage crashes on my iPhone using Safari and >> Firefox. I suspect that it’s trying to allocate too much memory. One >> curious thing that I’ve found with running Pari in my app is that it >> immediately claims the max stack size in memory when launching. For >> example, if I set the initial stack size to 4MB and the max stack size >> to 1GB, JavaScriptCore’s memory footprint will immediately balloon to >> 1GB upon running gp_embedded_init. I don’t know if it’s Emscripten’s >> or Pari’s doing or a strange interaction between Pari and Emscripten. >> Although I can confirm that this happens when visiting that webpage >> with Safari and Firefox on my Mac. I think if you were to set the >> maximum stack size to something smaller it would alleviate the problem >> and make it accessible on mobile. > > Thanks or the advice I have made some attempt to reduce memory usage. > Could you retry ? > >> Performance-wise, running GP in JavaScriptCore on my iPhone and even >> my iPad is much slower than using the browser GP implementation on my >> computer. Running fibonacci(1000000) on my iPad took between 3 to 5 >> minutes, whereas that same code running on my computer ran >> instantaneously. > > This is strange. Does JavaScriptCore support asm.js natively ? > Otherwise this might be due to "-s ALLOW_MEMORY_GROWTH”. The website works great on my iPhone now. It’s actually much faster than my app. I’m not sure why. I’ve built it using total_memory instead, but it’s still slow. JavaScriptCore doesn’t support asm.js, but neither does Safari, so I don’t know why the website is faster than my app. It could have something to do with the fact that I run it in a low-priority background thread. Maybe if I use a high-priority background thread it will be faster. I’ll try it and let you know. > >> Feature-wise, it does a little more than the browser GP >> implementation. Most notably, my app exposes iOS’s file system to >> Pari through some code that bridges Emscripten and NSFileManager. You >> can create and edit GP scripts, save them, and load them into GP at a >> later time. write(), read(), readstr(), etc also work since they go >> through Emscripten, which itself uses my bridge code. Other than that >> though, it is for all intents and purposes identical to GP on the >> website. >> >>> >>>> JavaScriptCore allows data to >>>> flow into and out of the JS virtual machine, which allows me to “hide” >>>> the JavaScript stuff behind a native UI and native functions (like >>>> file system operations). I’ve essentially bridged a text area to >>>> Emscripten’s stdout/stderr functions and a text input to gp_embedded. >>>> Here are the features directly related to Pari/GP that I’ve developed >>>> so far: >>> >>> How do you deal with the asynchronous nature of javascript ? >> >> Well, I use only the synchronous parts of JavaScript :). It turns out >> that only a few (important) parts of JavaScript are truly >> asynchronous, including XHR/Ajax and access to IndexedDB, both of >> which I avoid. I just point JavaScriptCore to the pari javascript >> file bundled with the app, so I don’t need XHR. That’s also the >> reason why I opted to bundle the memory file with emscripten-compiled >> pari file, so I won’t need XHR to load the memory file. And I don’t >> use IndexedDB, so that’s not a problem. Additionally, the javascript >> code is not running in a browser, so there is no need to wait for the >> DOM to be ready and no need for handling any events like button clicks >> and form submissions. The Emscripten-compiled code is loaded into >> JavaScriptCore with a simple function call and I proceed to use it by >> calling gp_embedded through Module.ccall. All of this is synchronous >> (or I should say, done on a single background thread to prevent the UI >> from locking up). >> >>> >>>> P.S. I built Pari/GP with a slightly modified build command than the >>>> one in the original post linked above: >>>> >>>> make -C Oemscripten-javascript "CC_FLAVOR= -s ALLOW_MEMORY_GROWTH=1 -s PRECISE_I64_MATH=1 -s EXPORTED_FUNCTIONS=[\'_main\',\'_gp_embedded\',\'_gp_embedded_init\'] --memory-init-file 0” >>> >>> I found that -s ALLOW_MEMORY_GROWTH=1 was slowing done GP too much, so now >>> I use -s TOTAL_MEMORY=1073741824 which limits the memory to 1GB. >>> WebAssembly seems not to have this problem. >> >> Thanks, I’ll try that next time! I might have to reduce the memory >> limit to 0.25GB or lower because the iPhone 6 and below only have 1GB >> of RAM. >> >>> >>> How do you handle the optional packages ? (galdata, elldata, etc.) >> >> So far I’ve only been working with the core Pari/GP functionality. >> However, now that I’m looking at the optional packages, they all >> appear to be data files. If that’s the case, then I can follow the >> instructions under the section that explains how to install them with >> an existing pari installation. Not only does Emscripten have an >> in-memory file system, it creates several directories that you would >> expect on a standard linux computer. When I run default on pari on my >> iPhone, it says that the datadir is /usr/local/share/pari, so I could >> put a menu somewhere in the app in which users could choose which >> optional packages to load into pari, at which point I’d load them into >> Emscripten’s file system in the datadir. I could even do this after >> Emscripten is set up but before pari initializes so pari would have >> those packages available to it from the start. I haven’t tried any of >> this yet, but I can’t see why it wouldn’t work. Emscripten and Pari >> are quite resilient :). The only issue that I can see is that the >> data would be too large to fit in memory, but the largest package is >> seadata-big at 220MB uncompressed, which is not unmanageable. Things >> start getting dicey when the app uses more than 0.75GB of memory, so >> limiting the stack size to 0.25GB should give us enough room to load >> every single package and stay below or not far beyond that threshold. >> We could also use the smaller versions of the packages. > > What the browser version does is to download only the files that are > actually read. Each files are smaller than 1MB, so this is usually > manageable. Unfortunately I do not know how to download files > synchronously. This might be possibe using the flag --proxy-to-worker > of emscripten but this requires a rewrite of the HTML file. > Instead I set a callback and restart the computation from scratch > once the file is received. This approach sounds better than what I was thinking of. I think a good middle ground would be to bundle the optional packages in the app or provide a way for users to download them into the app and load them on demand when Pari needs them as you do. Regard, Muhammad-Sharif Moustafa