Skip to content

Conversation

@jameshu15869
Copy link
Contributor

This PR implements utime for the JS API. I didn't find any tests for utime in the test directory, so added tests to test_fs_js_api.

I also attempted to add support for atime, mtime, and ctime nanoseconds in WasmFS. I am still a little new to C++ programming, so please let me know about any improvements I need to make to the implementation. One thing I wasn't sure about was how to get the nanoseconds - is using #include <time.h> the best way?

@jameshu15869 jameshu15869 marked this pull request as draft June 8, 2023 20:09
assert(ex.name === 'ErrnoError' && ex.errno == 8 /* EBADF */);
);

/********** test FS.utime() **********/
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if its worth splitting this function up. (That way the ones that are JS-only can also be written using EM_JS instead of EM_ASM)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Can be a followup PR for that)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, do you mean splitting up by moving each test section into an EM_JS function? Or should the code be split some other way?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup thats what I meant. Each section could be its own function (either a regular C function or an EM_JS function)


struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
atime_nsec = mtime_nsec = ctime_nsec = ts.tv_nsec;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is more comprehensive to support nanoseconds as well, and I think this the right way to do it (but we could also get the non-nanosecond times from this as well, to save the previous time(..) call).

However, I think we need to consider if we want to add ns. Technically a POSIX-compliant FS doesn't need that (I don't think POSIX guarantees a particular precision). And on the Web the timing info we get from Date.now() etc. may have limited resolution anyhow.

And, adding ns support has a cost in terms of code size. So overall I lean towards not adding it, and just documenting that decision.

@tlively what do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to removing the previous time call.

I would lean toward keeping this. I don't think it's too much of a stretch to imagine an Emscripten application that would want at least millisecond precision in the time stamps. For example, anything doing something similar to make to figure out when file changes mean something needs to be recomputed would need more than second precision.

I also expect that the code size increase would be fairly small.

time_t getATime() { return file->atime; }
long getATimeNs() { return file->atime_nsec; }
void setATime(time_t time) { file->atime = time; }
void setATimeNs(long time) { file->atime_nsec = time; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can combine these getters and setters? I imagine that usually the seconds and nanoseconds will always be set or retrieved at the same time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I was worried about compatibility with any code that used the old getters/setters by getting just the seconds with time(NULL). Would it be worth switching all of them to use a combined getter/setter? If so, would it be better to pass in the seconds and nanoseconds together as a pointer to a struct or two separate time_t and long values respectively?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, switching all the use sites would be fine. There shouldn't be many of them, and this is private API so this wouldn't be a breaking change. I would implement it by passing the timeval struct by value (rather than by pointer) since it is so small.

Comment on lines 326 to 327
ts.tv_sec = file->ctime;
ts.tv_nsec = file->ctime_nsec;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we stored the times on the file as timespecs, then this could just be return file->ctime;.

test_fs_utime();
test_fs_rmdir();
test_fs_close();
test_fs_mknod();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I think this makes the test much easier to read.

@jameshu15869
Copy link
Contributor Author

Currently my implementation has failed test_metadce_files_wasmfs and test_metadce_cxx_wasmfs. I was able to reproduce the issue locally, but am not sure of the cause. Could it be that using #include <time.h> in files.h and files.cpp is causing the error?

@sbc100
Copy link
Collaborator

sbc100 commented Jun 12, 2023

Can you run those tests with --rebase and then add the regressions to this PR. Its not unexpected that we will see slight regressions in wasmfs codesize test as you work on this stuff.

setMTime(time(NULL));
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
setMTime(ts);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to avoid this repeated code pattern somehow. If we did that then we would have a single place to change if we decided to get time information in another way in the future.

One option might be an updateMTime method which would mean "update to the current time". There might be a better name though?

Copy link
Contributor Author

@jameshu15869 jameshu15869 Jun 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree - would it also be helpful to have these "update to current time" functions for atime and ctime? Or is this only really needed for mtime?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For symmetry it might be nice to have it for them all, even if mtime is the most-repeating pattern.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option might be "updateTime" without mentioning mtime at all. Basically "this file was modified, update whatever time changes need to be done".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thinking making one "update to current time" for each time might be a good option here, since there were a few other spots where only atime and ctime also had to be set to the current time. Would that be fine for now?

@jameshu15869 jameshu15869 marked this pull request as ready for review June 13, 2023 17:20
@jameshu15869 jameshu15869 marked this pull request as draft June 13, 2023 17:21
@jameshu15869 jameshu15869 marked this pull request as ready for review June 13, 2023 19:41
},
// TODO: utime
utime: (path, atime, mtime) => {
return FS.handleError(withStackSave(() => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove the return here and the curly brace before it. Similar to #19614

#include <assert.h>
#include <fcntl.h>

EM_JS(void, test_fs_open, (), {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe make a separate PR for the test refactorings of existing tests?

@@ -1 +1 @@
51960
52403
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the cost of supporting nanoseconds, I suppose?

I am not sure it's worth it, personally. 500 bytes isn't a lot, but the benefit is unclear to me... but if you feel strongly @tlively I don't object.

Regardless, if we decide we want nanoseconds let's do it in its own PR?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think having better than second precision is worth 500 bytes. I'm surprised it costs that much, though.

@jameshu15869 jameshu15869 marked this pull request as draft June 14, 2023 20:34
@jameshu15869 jameshu15869 changed the title WasmFS JS API: Implement utime and add support for nanseconds WasmFS JS API: Implement utime Jun 14, 2023
kripken pushed a commit that referenced this pull request Jun 14, 2023
This PR refactors test_fs_js_api by placing each test into a separate method.
This PR was split from #19561
Copy link
Member

@tlively tlively left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM % stale TODOs.

@kripken
Copy link
Member

kripken commented Jun 15, 2023

Is this ready to land? (it's still marked "draft")

@jameshu15869
Copy link
Contributor Author

Oops, I forgot to set it as "ready" but the branch is ready to land.

@jameshu15869 jameshu15869 marked this pull request as ready for review June 16, 2023 01:31
@kripken kripken merged commit 51b99e1 into emscripten-core:main Jun 16, 2023
kripken pushed a commit that referenced this pull request Jun 21, 2023
This PR adds nanosecond support for file times in WasmFS, specifically when
used for utime and stat. This PR was separated from #19561
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants