[Stingray] Need something like performance.memory, need to figure out what

RESOLVED DUPLICATE of bug 1124223

Status

()

Core
DOM
RESOLVED DUPLICATE of bug 1124223
3 years ago
3 months ago

People

(Reporter: Tatsuto Horibe, Unassigned)

Tracking

Firefox Tracking Flags

(Not tracked)

Details

(Whiteboard: [MemShrink:P3])

(Reporter)

Description

3 years ago
In our stingray product, We face a problem to satisfy the requirement from major service vender. This service vender requests to support the following 2 APIs.

- window.performance.memory.totalJSHeapSize
- window.performance.memory.usedJSHeapSize
https://docs.webplatform.org/wiki/apis/timing/properties/memory

These may be not W3C standard, but we have to support it because this application is major service in world wide.

Comment 1

3 years ago
The summary at your page shows statement as below.
  "Do not use. Proprietary. Chrome only. Gets quantized scripting memory usage numbers. "

Q1: Do you expect this API can be used by which permission type - "certified", "privilieged" or web content?

Comment 2

3 years ago
Q2: could you confirm that [1] is the same issue with this bug?

Thanks.

[1] Bug 1124223 - implement performance.memory
Component: Performance → DOM
Flags: needinfo?(horibe.moz)
Product: Firefox OS → Core
(Reporter)

Comment 3

3 years ago
(In reply to Marco Chen [:mchen] (PTO from 16 Feb. to 22 Feb.) from comment #1)
> The summary at your page shows statement as below.
>   "Do not use. Proprietary. Chrome only. Gets quantized scripting memory
> usage numbers. "
> 
> Q1: Do you expect this API can be used by which permission type -
> "certified", "privilieged" or web content?

web content used it in iframe of privileged application.
Flags: needinfo?(horibe.moz)
(Reporter)

Comment 4

3 years ago
(In reply to Marco Chen [:mchen] (PTO from 16 Feb. to 22 Feb.) from comment #2)
> Q2: could you confirm that [1] is the same issue with this bug?
> 
> Thanks.
> 
> [1] Bug 1124223 - implement performance.memory

Yes, same issue.
Status: NEW → RESOLVED
Last Resolved: 3 years ago
Resolution: --- → DUPLICATE
Duplicate of bug: 1124223
Reopening, since the discussion in bug 1124223 makes it sound like we may want something rather different from what Chrome ships in performance.memory.

It would be good to get a clear explanation of what we _do_ want here.  If we're trying to measure memory for a single app (not a web page), and it's a sufficiently privileged app, then I would have no issues with exposing some of the jemalloc counters to it (things like heap-allocated and heap-mapped, say, which would kinda correspond to usedJSHeapSize and totalJSHeapSize except not restricted to the JS heap).

But the first step really is understanding what we're actually trying to measure and why.
Status: RESOLVED → REOPENED
Flags: needinfo?(horibe.moz)
Resolution: DUPLICATE → ---
Summary: [Stingray] performance.memory is not supported → [Stingray] Need something like performance.memory, need to figure out what
Whiteboard: [MemShrink]
See Also: → bug 1124223
Whiteboard: [MemShrink] → [MemShrink:P3]
(Reporter)

Comment 7

3 years ago
According to the service vender's explanation,
they want to know how much memory is used for the app at any timing
so that they are able to detect how much larger they can use at that moment.
It's necessary to improve the performance.

And they are saying that totalJSHeapSize is not important.
It is ok that totalJSHeapSize is fixed as 150Mbyte
as long as at least 150Mbyte memory is secured for only this app.

Here are what we need to gurantee as for JSHeapSize.
1. At least 150Mbyte memory should be secured for only the specific app.
   (totalJSHeapSize must be over 150Mbyte)
2. Need to avoid a lack of memory while usedJSHeapSize is not over totalJSHeapSize.
Flags: needinfo?(horibe.moz)
OK, so they don't care about the JS heap at all.  They care about total memory usage, which includes all sorts of things that don't live in the JS heap, and they care about available memory (which is not the same thing as totalJSHeapSize at all).

Is this going to be a certified app?  A privileged app?  Something else?

Do they plan to check the "used" value often?  As in, how fast does that accessor need to be?

They do realize that "lack of memory" can occur no matter what due to heap fragmentation, depending on what they're allocating, right?  :(
Flags: needinfo?(horibe.moz)
I echo bz's comments and add that things are not set up to guarantee any app a particular amount of memory. It just doesn't work that way and it can't be tacked on.
(Reporter)

Comment 10

3 years ago
> Is this going to be a certified app?  A privileged app?  Something else?

In their web application in their server.
But it runs in iframe of our wrapper privileged application.

> Do they plan to check the "used" value often?  As in, how fast does that
> accessor need to be?

I don't know but not so often, I think.

> They do realize that "lack of memory" can occur no matter what due to heap
> fragmentation, depending on what they're allocating, right?  :(

I understand, may be acceptable.
Flags: needinfo?(horibe.moz)
> But it runs in iframe of our wrapper privileged application.

OK.  So if we exposed an API in privileged apps only, that would address this particular use case.  

I would probably be ok with doing that... If we wanted to, we could even restrict it to the particular domain in question.  Jonas, any objections?
Flags: needinfo?(jonas)
Comment 7 sounds like the goal here is bigger than just measure how much memory is used. It also sounds like the goal is to guarantee that an app has 150MB of data available? And guarantee that the app won't get OOM killed until it uses that much memory.

That would require a totally different thing than the Chrome API in comment 1.

So could someone clarify, do we want what's in comment 7 or what's in comment 1.
Flags: needinfo?(jonas)
(Reporter)

Comment 13

3 years ago
I don't know the detail specification of Chrome API in comment 1.
But just know, our minimum requirement is comment 7.
This requirement is urgent issue for our stingray product.
Thank you for your support.
So if I understand correctly, what is requested here are:

* The ability for an app to "preallocate" 150MB of memory (can this number be chosen by the app?)
* A promise that the application won't be killed as long as it uses less memory than that number.

The Chrome API does neither of those things, so I think we should stop talking about the Chrome API.

This capability is very different from the current architecture of FirefoxOS, so it will require a lot of work to implement. I don't know who would have the experience and time to do so. But I doubt anyone on the platform team does.

So likely this would either fall on the partner, or on the devices team.

Again, these comments only apply if what we want is the API in comment 7, not the API in comment 1.
The team that's implementing this would also have to answer questions like:

* What happens if three apps try to allocate 150MB of memory, but the device only has 400MB of memory
  available to apps.
* What happens if there's a background app which has allocated a lot of memory, but the front-most app
  hasn't allocated any memory, and then we run low on memory. Do we kill the front-most app first?
(Reporter)

Comment 16

3 years ago
(In reply to Jonas Sicking (:sicking) from comment #15)
> The team that's implementing this would also have to answer questions like:
> 
> * What happens if three apps try to allocate 150MB of memory, but the device
> only has 400MB of memory
>   available to apps.
> * What happens if there's a background app which has allocated a lot of
> memory, but the front-most app
>   hasn't allocated any memory, and then we run low on memory. Do we kill the
> front-most app first?

Our "memory-pressure" event is notified under 100MB of rest memory on device.
And background app is killed first.

So, the following function in comment 14 is not necessary, I think.
> * The ability for an app to "preallocate" 150MB of memory (can this number be chosen by the app?)
> * A promise that the application won't be killed as long as it uses less memory than that number.

Thanks.
(Reporter)

Comment 18

3 years ago
> So, the following function in comment 14 is not necessary, I think.

Correction.
The functions in comment 14 may be satisfied by application management based on "memory-pressure" event.

Thanks.
Tatsuto: If you want help from me, you need to provide more clear requirements. Comments 0, 7, 14 and 18 are very contradictory.

Maybe rather than providing suggestions for API, it would be good to understand what the partner is trying to do, what doesn't work well in FirefoxOS right now and if/how this has worked better on other platforms.
(Reporter)

Comment 20

3 years ago
(In reply to Jonas Sicking (:sicking) from comment #19)
> Tatsuto: If you want help from me, you need to provide more clear
> requirements. Comments 0, 7, 14 and 18 are very contradictory.

Sorry for confusing you.
Comment 7 is the answer of bug 1124223 comment 4.
This is the reason/background to need performance.memory API for "service vender".
Comment 7 is the requirement of "service vender" to "device manufacture", not my requirement to you.

We have to support performance.memory API to archive the certification of this service.
I want your support/advice in the following points.
- How to implement these API, especially how to get the used JS heap size.
- How do you consider the permission issue to access these API.

Comment 21

3 years ago
Hi,

Will discuss with partner then get back the conclusion here.

Comment 22

3 years ago
(In reply to Tatsuto Horibe from comment #3)
> (In reply to Marco Chen [:mchen] (PTO from 16 Feb. to 22 Feb.) from comment
> > Q1: Do you expect this API can be used by which permission type -
> > "certified", "privilieged" or web content?
> 
> web content used it in iframe of privileged application.

By the way, I want to make sure the statement here.
We all understand that we can limit an API by privileged permission type.
But the statement here seems to be
  1. To have a privileged application but just as a wrapper only.
  2. Inside this app, an i-frame element will be created and points to the web page on the remote server. (maybe they are on the same domain name) 

In this case, according to different origin (app:// and http://) I don't think this web page loaded by iframe can access APIs limited by privilieged permissions.

Therefore even the requirements are just as what comment 1 mentioned, it is still a problem here.
We can write a custom function to enable based on permissions of the topmost frame or whatever.  That part is not a showstopper.

Comment 24

3 years ago
(In reply to Marco Chen [:mchen] (PTO from 16 Feb. to 22 Feb.) from comment #21)
> Hi,
> 
> Will discuss with partner then get back the conclusion here.

After discussing with partner offline, the conclusion are

  1. This bug should focus the requirement from Comment 1 only.

  2. About 150MB, that is another requirement from service provider but is not directly related to this API. It is a kind of certification that asks platform to secure the proper memory size for it. Therefore there should be an another mechanism to achieve this.

Hi bz, njn and Jonas,

Then please continue the discussion which focused on comment 1. Thanks.

Comment 25

3 years ago
(In reply to Not doing reviews right now from comment #11)
> > But it runs in iframe of our wrapper privileged application.
> 
> OK.  So if we exposed an API in privileged apps only, that would address
> this particular use case.  
> 
> I would probably be ok with doing that... If we wanted to, we could even
> restrict it to the particular domain in question.  Jonas, any objections?

Also related to comment 23 and 22.

I would like to know the proposed permission model for this kind of API. After I read all these comments, it might be

  P1. be limited by privileged permission type. 
    (But this will be fulfilled the use case from partner - comment 22)
  P2. based on P1 and add more rules to allow web pages which are not located on the Web App Package to access this API. (comment 11 & 23)

Updated

3 years ago
Flags: needinfo?(jonas)
Flags: needinfo?(bzbarsky)
>  1. This bug should focus the requirement from Comment 1 only.

In that case, I would like answers to my questions from bug 1124223 comment 4.

> I would like to know the proposed permission model for this kind of API.

Given the information in this bug, it would be just a normal permissions check, but on the toplevel window, not the window the API is being accessed on.  At least assuming that we trust the privileged app to not screw up.
Flags: needinfo?(bzbarsky) → needinfo?(mchen)

Updated

3 years ago
Flags: needinfo?(mchen) → needinfo?(horibe.moz)

Comment 27

3 years ago
(In reply to Not doing reviews right now from comment #26)
> >  1. This bug should focus the requirement from Comment 1 only.
> 
> In that case, I would like answers to my questions from bug 1124223 comment
> 4.
> 
> > I would like to know the proposed permission model for this kind of API.
> 

I am not sure about this part yet. 

From my personal opinion it seems that app would like to know how many memory are avaliable then app can ask more memory for improving the performance like increasing the media data buffer therefore the playback can be kept smooth without buffer starvation (like what Horibe mentioned about MSE).

That mean from app point of view, it don't care what are the definition of JSObject or JSHeap but only care about how many memory it can try to leverage. (API tells me "totalJSHeapSize is A" and "usedJSHeapSize is B", then the playback time I can buffered is "(A - B - reserved) / bitrate")

Hi Horibe,

Is my statement as your thought or
could you check with your service provider then give more accurate feedback here?

> Given the information in this bug, it would be just a normal permissions
> check, but on the toplevel window, not the window the API is being accessed
> on.  At least assuming that we trust the privileged app to not screw up.

The key point is your last statement and that might be judged by security team.
If this is real then all of the privileged app can just have an empty package with one i-frame element pointed to real resources on the remote server. But maybe attacker can inject JS script into the network transaction then this app screw up the system.
> API tells me "totalJSHeapSize is A" and "usedJSHeapSize is B", then the playback time I
> can buffered is "(A - B - reserved) / bitrate"

This is totally wrong, because there are lots of things that are in memory but not on the JS heap.
I think we'll need bz's input too, but here are my thoughts:

* We should not worry about matching Chrome's API exactly. I'm fairly certain that their API doesn't take
  into account things like image data usage, DOM object usage and layout structures usage. So there should
  be no expectation that you won't OOM just because you stay within totalJSHeapSize.
* That also means that I don't think we need to worry too much about shared objects. We should do whatever
  is easiest, be that to not count shared objects at all, or to count all shared object, or something in
  between.
* If we can ensure that the API doesn't expose data about other origins, then I think it's fine to expose
  this API to all web pages on *this* TV product only. I.e. I don't think we should expose it in any
  other releases of FirefoxOS.
* One possible strategy would be measure the memory use from the compartment that the page uses.
* I would imagine that Chrome has hooked into some internal properties that are used by their GC logic.
  If we have anything similar it would be nice to use that, even if it's not a perfect match?
* If we don't have anything like this available, or it would be hard to limit to the current
  compartment/origin, then I think we need to simply tell the partner that this API is too specific to
  Chrome's internal architecture and we can look at if there are other ways to solve whatever problem that
  they are trying to solve. I.e. I don't want to start building a privileged version or some such without
  talking to the partner first.
Flags: needinfo?(jonas)

Comment 30

3 years ago
(In reply to Not doing reviews right now from comment #28)
> > API tells me "totalJSHeapSize is A" and "usedJSHeapSize is B", then the playback time I
> > can buffered is "(A - B - reserved) / bitrate"
> 
> This is totally wrong, because there are lots of things that are in memory
> but not on the JS heap.

Hi bz,

Thanks for pointing this and I don't really understand the JS heap indeed.

What I mentioned here is based on https://bugzilla.mozilla.org/show_bug.cgi?id=1124223#c6 .
From app point of view, I don't care what is the rule inside the UA to report these two values.
I just want to know "how much memory I can still try to use" from this API.
And of course we need partner to confirm or input the motivation that why the targeted web page uses this API.

Based on my assumption
  1. the totalJSHeapSize is a kind of maximum value which UA will not allow web page to use memory exceeding this value. (It seems that FxOS now doesn't have this limitation yet?)
  2. but it didn't mean UA will secure this amount of memory for this page.
  3. then the app might get totalJSHeapSize as smaller size if the system memory is lower then max value. (can have more rules to calculate it)
  4. so app still need to deal with the case that "new JS object" will be failed even the report from API allows app to do this.

Hi Horibe,

maybe my assumption of the requirement is still wrong. Could you help to confirm this?
(For securing 150mb issue, we should separate it from this API. That can be done by platform level not on the API definition. ex: product customization for some key apps)

Thanks.
>  1. the totalJSHeapSize is a kind of maximum value which UA will not allow web page to
>  use memory exceeding this value. 

We don't have such a concept in Gecko or SpiderMonkey right now, fwiw.

That's also not what it means in Chrome.  In Chrome, afaict performance.memory exposes three numbers:

1)  usedJSHeapSize.  This is the SizeOfObjects() metric from the V8 heap, which seems to correspond to an estimate (it's not exact when called while stuff is being swept) for the size of the "live" object heap.

2)  totalJSHeapSize.  This is the CommittedPhysicalMemory() from the V8 heap.  I haven't dug into the full complexity of their memory allocation setup, but this _seems_ like how much memory they've asked the OS for for the various spaces in the V8 heap.  This is clearly larger than usedJSHeapSize but can also have slop due to freelists things that haven't been swept yet, and probably other things; I didn't look into the details too much.

3)  jsHeapSizeLimit.  This is the MaxReserved from the V8 heap.  It's basically the size of their nurseries (which is fixed at 32MB on 32-bit and 64MB on 64-bit) plus the absolute cap they set on the JS heap ever (currently 700MB on 32-bit and 1400MB on 64-bit).

All of these numbers are also rounded somewhat, with the upshot being that jsHeapSizeLimit is actually larger than the heap size that will cause V8 to fail allocations and crash the renderer process.

>  2. but it didn't mean UA will secure this amount of memory for this page.

Correct.

> 3. then the app might get totalJSHeapSize as smaller size if the system memory is lower

totalJSHeapSize, at least in V8's incarnation, just tells you how much stuff you have so far allocated out of the JS heap.  It's at best loosely related to how much stuff you've allocated in general, and totally unrelated to the amount of physical RAM around.
(Reporter)

Comment 32

3 years ago
Marco and all, thank you for your support.

(In reply to Marco Chen [:mchen] from comment #30)
> Based on my assumption
>   1. the totalJSHeapSize is a kind of maximum value which UA will not allow
> web page to use memory exceeding this value. (It seems that FxOS now doesn't
> have this limitation yet?)

Yes, same as I expected. but this is different with Chrome API spec (comment 31) and Gecko's concept, it is OK the suggestion by jonas-san in commment 29, easiest way for our device only.

>   4. so app still need to deal with the case that "new JS object" will be
> failed even the report from API allows app to do this.

If is is difficult, it is acceptable to kill this app.
or usedJSHeapSize returns the same value with totalJSHeapSize.

> (For securing 150mb issue, we should separate it from this API. That can be
> done by platform level not on the API definition. ex: product customization
> for some key apps)

Yes, I think so.

Thanks.
Flags: needinfo?(horibe.moz)
(In reply to Marco Chen [:mchen] from comment #30)
> I just want to know "how much memory I can still try to use" from this API.

Ok, I think that's totally different from what the Chrome API answers. So if this is what we want to know, then we should stop talking about the Chrome API.

> Based on my assumption
>   1. the totalJSHeapSize is a kind of maximum value which UA will not allow
> web page to use memory exceeding this value. (It seems that FxOS now doesn't
> have this limitation yet?)

My understanding is that it's something completely different. It's a sort of maximum memory that the page has used *for JS objects* until this point in time.

So it has nothing to do with how much memory is used in total since it only includes JS objects.

It also has nothing to do with how much memory the page can use. I.e. if the page tries to use more memory this number will simply be increased.

usedJSHeapSize is similar, but it's indicating how much the page is using for JS objects right now. Again, this only includes JS objects and not a lot of other things. And again, this is not a limit of any sort and will simply grow if the page tries to use more.


Has the partner asked us to implement the Chrome API because they have pages that use it?

Or does the partner have a problem that they would like to solve, and they hoped that the Chrome API would solve it?

Or both?

Comment 34

3 years ago
(In reply to Jonas Sicking (:sicking) from comment #33)
>> totalJSHeapSize
> My understanding is that it's something completely different. It's a sort of
> maximum memory that the page has used *for JS objects* until this point in
> time.
>
> So it has nothing to do with how much memory is used in total since it only
> includes JS objects.

Now understand that it only count JS objects in and thanks.

> 
> It also has nothing to do with how much memory the page can use. I.e. if the
> page tries to use more memory this number will simply be increased.

Refer to [1], it shows 
   "totalJsHeapSize is current size of the JS heap including FREE SPACE not occupied by any JS objects" 

From my understanding, the "free space" seems to mean "how much free memory you can take from JS heap now".

   "usedJsHeapSize is the total amount of memory being used by JS objects including V8 internal objects"

For me, it means how much memory you used NOW for JS objects. Combining these information, I still think the difference between "totoalJSHeapSize and usedJsHeapSize" can imply how much memory you can use for asking new JS objects now.

And one question for me is the definition of "jsHeapSizeLimit". 
It seems that "totalJsHeapSize" is the current JS heap size only and this size can be changed in run time. But it can't always be bigger then "jsHeapSizeLimit". If so there might be some algorithm or rules for adjusting the heap size.

------------------

In the example of MSE use case, it will try to do "new Uint8Array()" then fit into MediaSource object. So I feel that if I can know how much free memory in JS heap then I can improve my self for the buffers to MediaSource. (and of couse the page should know others JS objects will use them as well)


[1] https://docs.webplatform.org/wiki/apis/timing/properties/memory#Notes
[2] https://bugs.webkit.org/show_bug.cgi?id=94534 (searching the key word "globalData->heap.capacity")

> 
> Has the partner asked us to implement the Chrome API because they have pages
> that use it?
> 
> Or does the partner have a problem that they would like to solve, and they
> hoped that the Chrome API would solve it?
> 
> Or both?


Hi Horibe,

Could you help to double confirm 
  1. the service provider just take care about "totalJsHeapSize" and "usedJSHeapSize"?
  2. what is the definition or understanding from service provider to use these parameters?
  3. how service provider think the relationship between "totalJsHeapSize" and "jsHeapSizeLimit"?
  4. does service provider has pages using these API directly?
  5. what is the purpose of using these APIs by service provider? (if possible, could they give a sample use case?)

Thanks.
Flags: needinfo?(horibe.moz)
> Now understand that it only count JS objects in and thanks.

Note that "JS objects" is a finicky concept, too.

> From my understanding, the "free space" seems to mean "how much free memory you can take
> from JS heap now".

It doesn't, per my reading of the V8 code, since "free space" afaict includes objects that are known dead but have not been swept yet.  As in, it includes space that will become free sometime soon but isn't actually free now.

> In the example of MSE use case, it will try to do "new Uint8Array()" then fit into
> MediaSource object. So I feel that if I can know how much free memory in JS heap then I
> can improve my self for the buffers to MediaSource. 

Just so we're on the same page, I recommend running this testcase in Chrome:

  <pre><script>
  document.writeln(JSON.stringify(performance.memory));
  var buffer = new Uint8Array(500000000);
  document.writeln(JSON.stringify(performance.memory));
  for (var i = 0; i < 500000000; ++i) buffer[i] = i;  
  document.writeln(JSON.stringify(performance.memory));
  </script>

To save you the suspense, the totalJSHeapSize in all three of those writeln() calls is 10000000 over here.  So clearly the memory used for the Uint8Array's backing buffer is not being included in totalJSHeapSize.

Or try this in Chrome:

  <pre><script>
  document.writeln(JSON.stringify(performance.memory));
  var buffer = new Array(60000000);
  document.writeln(JSON.stringify(performance.memory));
  for (var i = 0; i < 60000000; ++i) buffer[i] = i;  
  document.writeln(JSON.stringify(performance.memory));
  </script>

Over here, that suggests that array storage is not included in the performance.memory numbers either....

I agree that answers to your questions would be good to have, though.
(Reporter)

Comment 36

3 years ago
(In reply to Marco Chen [:mchen] from comment #34)
> Hi Horibe,
> 
> Could you help to double confirm 
>   1. the service provider just take care about "totalJsHeapSize" and
> "usedJSHeapSize"?

Yes.

>   2. what is the definition or understanding from service provider to use
> these parameters?

The service provider says only, 
2. Need to avoid a lack of memory while usedJSHeapSize is not over totalJSHeapSize.

>   3. how service provider think the relationship between "totalJsHeapSize"
> and "jsHeapSizeLimit"?

jsHeapSizeLimit is not their requirement.

>   4. does service provider has pages using these API directly?

Yes.

>   5. what is the purpose of using these APIs by service provider? (if
> possible, could they give a sample use case?)

The service provider says,
"It's necessary to improve the performance."

> In the example of MSE use case, it will try to do "new Uint8Array()" then
> fit into MediaSource object. So I feel that if I can know how much free
> memory in JS heap then I can improve my self for the buffers to MediaSource.
> (and of couse the page should know others JS objects will use them as well)

I also think that this is the purpose of using these APIs by service provider.

Thanks.
> 2. Need to avoid a lack of memory while usedJSHeapSize is not over totalJSHeapSize.

Note that Chrome provides no such guarantees or anything resembling them, per above, unless I'm seriously missing something.
(Reporter)

Comment 38

3 years ago
We had feedback from service provider.
- At the moment, these APIs are not used in this service.
- They have a plan to use these APIs in the future.
- The purpose of using these APIs is not for media source buffering but for the performance of UI in the media contents list.

BTW, our first stingray product will be launched soon.
So, I have opened the new bug as private one and propose the solution for only our product in [1].

[1] https://bugzilla.mozilla.org/show_bug.cgi?id=1141486

Thanks.
Flags: needinfo?(horibe.moz)

Updated

3 years ago
Blocks: 1092900
Status: REOPENED → RESOLVED
Last Resolved: 3 years ago3 months ago
Resolution: --- → DUPLICATE
Duplicate of bug: 1124223
You need to log in before you can comment on or make changes to this bug.