59 FORCE_INLINE void SetWritable(SPageInfo& aPageInfo) |
67 FORCE_INLINE void SetWritable(SPageInfo& aPageInfo) |
60 { |
68 { |
61 if (!aPageInfo.IsDirty()) |
69 if (!aPageInfo.IsDirty()) |
62 {// This is the first mapping to write to the page so increase the |
70 {// This is the first mapping to write to the page so increase the |
63 // dirty page count. |
71 // dirty page count. |
64 aPageInfo.SetWritable(); |
|
65 iNumberOfDirtyPages++; |
72 iNumberOfDirtyPages++; |
66 } |
73 } |
|
74 aPageInfo.SetWritable(); |
67 } |
75 } |
68 |
76 |
69 FORCE_INLINE void SetClean(SPageInfo& aPageInfo) |
77 FORCE_INLINE void SetClean(SPageInfo& aPageInfo) |
70 { |
78 { |
71 __NK_ASSERT_DEBUG(iNumberOfDirtyPages); |
79 __NK_ASSERT_DEBUG(iNumberOfDirtyPages); |
242 TBool ReservePages(TUint aRequiredCount, TUint& aCount); |
250 TBool ReservePages(TUint aRequiredCount, TUint& aCount); |
243 |
251 |
244 /** |
252 /** |
245 */ |
253 */ |
246 void UnreservePages(TUint& aCount); |
254 void UnreservePages(TUint& aCount); |
|
255 |
|
256 /** |
|
257 Indicates whether there are any dirty pages available to be cleaned by #CleanSomePages. |
|
258 |
|
259 This is called by the page cleaner to work out whether it has any work to do. |
|
260 |
|
261 @return Whether there are any dirty pages in the oldest section of the live list. |
|
262 */ |
|
263 TBool HasPagesToClean(); |
|
264 |
|
265 /** |
|
266 Attempt to clean one or more dirty pages in one go. |
|
267 |
|
268 Called by the page cleaner to clean pages and by PageInAllocPage when needs to steal a page from |
|
269 the live list, but the oldest clean list is empty. |
|
270 |
|
271 May or may not succeed in acually cleaning any pages. |
|
272 |
|
273 @param aBackground Whether the activity should be ignored when determining whether the paging |
|
274 device is busy. This is used by the page cleaner. |
|
275 |
|
276 @return The number of pages this method attempted to clean. If it returns zero, there were no |
|
277 pages eligible to be cleaned. |
|
278 */ |
|
279 TInt CleanSomePages(TBool aBackground); |
247 |
280 |
248 /** |
281 /** |
249 Enumeration of instrumented paging events which only require the |
282 Enumeration of instrumented paging events which only require the |
250 SPageInfo object as an argument. |
283 SPageInfo object as an argument. |
251 */ |
284 */ |
304 @param aBlockRest Set to ETrue when we don't want the allocator to search for new pages if the RAM |
337 @param aBlockRest Set to ETrue when we don't want the allocator to search for new pages if the RAM |
305 zone with ID==aBlockZoneId is encountered, i.e. a general RAM defrag operation. |
338 zone with ID==aBlockZoneId is encountered, i.e. a general RAM defrag operation. |
306 */ |
339 */ |
307 TInt DiscardPage(SPageInfo* aOldPageInfo, TUint aBlockZoneId, TBool aBlockRest); |
340 TInt DiscardPage(SPageInfo* aOldPageInfo, TUint aBlockZoneId, TBool aBlockRest); |
308 |
341 |
|
342 /** |
|
343 Attempt to discard the specified page and then allocate a page of type aPageType |
|
344 in its place. |
|
345 |
|
346 @param aPageInfo The page info of the page to discard. |
|
347 @param aPageType The new page type to allocate into aPageInfo's physical address. |
|
348 */ |
|
349 TInt DiscardAndAllocPage(SPageInfo* aPageInfo, TZonePageType aPageType); |
|
350 |
309 |
351 |
310 /** |
352 /** |
311 Update any live list links to replace the old page with the new page. |
353 Update any live list links to replace the old page with the new page. |
312 This is to be used when a page has been moved. |
354 This is to be used when a page has been moved. |
313 |
355 |
355 @post MmuLock left unchanged. |
397 @post MmuLock left unchanged. |
356 */ |
398 */ |
357 void RemovePage(SPageInfo* aPageInfo); |
399 void RemovePage(SPageInfo* aPageInfo); |
358 |
400 |
359 /** |
401 /** |
|
402 Try to remove the oldest page from the live page list and perform #StealPage. |
|
403 |
|
404 @param aPageInfoOut Set to the SPageInfo pointer for the stolen page if any. |
|
405 |
|
406 @return KErrNone on success, KErrInUse if stealing failed or 1 to indicate the the oldest page |
|
407 was dirty and the PageCleaning mutex was not held. |
|
408 |
|
409 @pre MmuLock held |
|
410 @post MmuLock left unchanged. |
|
411 */ |
|
412 TInt TryStealOldestPage(SPageInfo*& aPageInfoOut); |
|
413 |
|
414 /** |
360 Remove the oldest page from the live page list and perform #StealPage. |
415 Remove the oldest page from the live page list and perform #StealPage. |
361 |
416 |
362 @pre MmuLock held |
417 @pre MmuLock held |
363 @post MmuLock left unchanged. |
418 @post MmuLock held (but may have been released by this function) |
364 */ |
419 */ |
365 SPageInfo* StealOldestPage(); |
420 SPageInfo* StealOldestPage(); |
366 |
421 |
367 /** |
422 /** |
368 Steal a page from the memory object (if any) which is using the page. |
423 Steal a page from the memory object (if any) which is using the page. |
369 If successful the returned page will be in the EUnknown state and the |
424 If successful the returned page will be in the EUnknown state and the |
370 cache state for the page is indeterminate. This is the same state as |
425 cache state for the page is indeterminate. This is the same state as |
371 if the page had been allocated by Mmu::AllocRam. |
426 if the page had been allocated by Mmu::AllocRam. |
372 |
427 |
373 @pre RamAlloc mutex held |
428 @pre RamAlloc mutex held |
|
429 @pre If the page is dirty the PageCleaning lock must be held. |
374 @pre MmuLock held |
430 @pre MmuLock held |
375 @post MmuLock held (but may have been released by this function) |
431 @post MmuLock held (but may have been released by this function) |
376 */ |
432 */ |
377 TInt StealPage(SPageInfo* aPageInfo); |
433 TInt StealPage(SPageInfo* aPageInfo); |
378 |
434 |
424 1. An unused page in the live page list. |
480 1. An unused page in the live page list. |
425 2. The systems free pool. |
481 2. The systems free pool. |
426 3. The oldest page from the live page list. |
482 3. The oldest page from the live page list. |
427 */ |
483 */ |
428 SPageInfo* PageInAllocPage(Mmu::TRamAllocFlags aAllocFlags); |
484 SPageInfo* PageInAllocPage(Mmu::TRamAllocFlags aAllocFlags); |
|
485 |
|
486 /** |
|
487 Called by CleanSomePages() to determine which pages should be cleaned. |
|
488 |
|
489 This deals with the complexity of page colouring, which means that pages can only be mapped at |
|
490 certain locations. When cleaning multiple pages at once we need to find a set of pages that we |
|
491 can map in memory sequentially. |
|
492 |
|
493 @pre MmuLock held |
|
494 |
|
495 @param aPageInfosOut Pointer to an array of SPageInfo pointers, which must be at least |
|
496 KMaxPagesToClean long. This will be filled in to indicate the pages to clean. |
|
497 |
|
498 @return The numnber of pages to clean. |
|
499 */ |
|
500 TInt SelectPagesToClean(SPageInfo** aPageInfosOut); |
429 |
501 |
430 /** |
502 /** |
431 If the number of young pages exceeds that specified by iYoungOldRatio then a |
503 If the number of young pages exceeds that specified by iYoungOldRatio then a |
432 single page is made 'old'. Call this after adding a new 'young' page. |
504 single page is made 'old'. Call this after adding a new 'young' page. |
433 |
505 |
519 TUint16 iYoungOldRatio; /**< Ratio of young to old pages in the live page list */ |
591 TUint16 iYoungOldRatio; /**< Ratio of young to old pages in the live page list */ |
520 SDblQue iYoungList; /**< Head of 'young' page list. */ |
592 SDblQue iYoungList; /**< Head of 'young' page list. */ |
521 TUint iYoungCount; /**< Number of young pages */ |
593 TUint iYoungCount; /**< Number of young pages */ |
522 SDblQue iOldList; /**< Head of 'old' page list. */ |
594 SDblQue iOldList; /**< Head of 'old' page list. */ |
523 TUint iOldCount; /**< Number of old pages */ |
595 TUint iOldCount; /**< Number of old pages */ |
524 #ifdef _USE_OLDEST_LISTS |
|
525 SDblQue iOldestCleanList; /**< Head of 'oldestClean' page list. */ |
596 SDblQue iOldestCleanList; /**< Head of 'oldestClean' page list. */ |
526 TUint iOldestCleanCount; /**< Number of 'oldestClean' pages */ |
597 TUint iOldestCleanCount; /**< Number of 'oldestClean' pages */ |
527 SDblQue iOldestDirtyList; /**< Head of 'oldestDirty' page list. */ |
598 SDblQue iOldestDirtyList; /**< Head of 'oldestDirty' page list. */ |
528 TUint iOldestDirtyCount; /**< Number of 'oldestDirty' pages */ |
599 TUint iOldestDirtyCount; /**< Number of 'oldestDirty' pages */ |
529 TUint16 iOldOldestRatio; /**< Ratio of old pages to oldest to clean and dirty in the live page list*/ |
600 TUint16 iOldOldestRatio; /**< Ratio of old pages to oldest to clean and dirty in the live page list*/ |
530 #endif |
|
531 TUint iNumberOfFreePages; |
601 TUint iNumberOfFreePages; |
532 TUint iNumberOfDirtyPages; /**< The total number of dirty pages in the paging cache. Protected by MmuLock */ |
602 TUint iNumberOfDirtyPages; /**< The total number of dirty pages in the paging cache. Protected by MmuLock */ |
533 TUint iInitMinimumPageCount;/**< Initial value for iMinimumPageCount */ |
603 TUint iInitMinimumPageCount;/**< Initial value for iMinimumPageCount */ |
534 TUint iInitMaximumPageCount;/**< Initial value for iMaximumPageCount */ |
604 TUint iInitMaximumPageCount;/**< Initial value for iMaximumPageCount */ |
535 TUint iReservePageCount; /**< Number of pages reserved for locking */ |
605 TUint iReservePageCount; /**< Number of pages reserved for locking */ |
537 iMinimumPageCount >= iMinimumPageLimit + iReservePageCount */ |
607 iMinimumPageCount >= iMinimumPageLimit + iReservePageCount */ |
538 SVMEventInfo iEventInfo; |
608 SVMEventInfo iEventInfo; |
539 |
609 |
540 #ifdef __DEMAND_PAGING_BENCHMARKS__ |
610 #ifdef __DEMAND_PAGING_BENCHMARKS__ |
541 public: |
611 public: |
542 void RecordBenchmarkData(TPagingBenchmark aBm, TUint32 aStartTime, TUint32 aEndTime); |
612 void RecordBenchmarkData(TPagingBenchmark aBm, TUint32 aStartTime, TUint32 aEndTime, TUint aCount); |
543 void ResetBenchmarkData(TPagingBenchmark aBm); |
613 void ResetBenchmarkData(TPagingBenchmark aBm); |
|
614 void ReadBenchmarkData(TPagingBenchmark aBm, SPagingBenchmarkInfo& aDataOut); |
|
615 TSpinLock iBenchmarkLock; |
544 SPagingBenchmarkInfo iBenchmarkInfo[EMaxPagingBm]; |
616 SPagingBenchmarkInfo iBenchmarkInfo[EMaxPagingBm]; |
545 #endif //__DEMAND_PAGING_BENCHMARKS__ |
617 #endif //__DEMAND_PAGING_BENCHMARKS__ |
546 }; |
618 }; |
547 |
619 |
548 extern DPager ThePager; |
620 extern DPager ThePager; |
549 |
621 |
550 |
622 |
551 #ifdef __DEMAND_PAGING_BENCHMARKS__ |
623 #ifdef __DEMAND_PAGING_BENCHMARKS__ |
552 |
624 |
553 #define START_PAGING_BENCHMARK TUint32 _bmStart = NKern::FastCounter() |
625 #define START_PAGING_BENCHMARK TUint32 _bmStart = NKern::FastCounter() |
554 #define END_PAGING_BENCHMARK(bm) ThePager.RecordBenchmarkData(bm, _bmStart, NKern::FastCounter()) |
626 #define END_PAGING_BENCHMARK(bm) ThePager.RecordBenchmarkData(bm, _bmStart, NKern::FastCounter(), 1) |
|
627 #define END_PAGING_BENCHMARK_N(bm, n) ThePager.RecordBenchmarkData(bm, _bmStart, NKern::FastCounter(), (n)) |
555 |
628 |
556 #else |
629 #else |
557 |
630 |
558 #define START_PAGING_BENCHMARK |
631 #define START_PAGING_BENCHMARK |
559 #define END_PAGING_BENCHMARK(bm) |
632 #define END_PAGING_BENCHMARK(bm) |
|
633 #define END_PAGING_BENCHMARK_N(bm, n) |
560 #endif // __DEMAND_PAGING_BENCHMARKS__ |
634 #endif // __DEMAND_PAGING_BENCHMARKS__ |
561 |
635 |
562 |
636 |
563 FORCE_INLINE void DPager::Event(TEventSimple aEvent, SPageInfo* aPageInfo) |
637 FORCE_INLINE void DPager::Event(TEventSimple aEvent, SPageInfo* aPageInfo) |
564 { |
638 { |
696 Multiplier for number of request objects in pool per drive that supports paging. |
770 Multiplier for number of request objects in pool per drive that supports paging. |
697 */ |
771 */ |
698 const TInt KPagingRequestsPerDevice = 2; |
772 const TInt KPagingRequestsPerDevice = 2; |
699 |
773 |
700 |
774 |
701 class DPagingRequest; |
775 class DPoolPagingRequest; |
702 class DPageReadRequest; |
776 class DPageReadRequest; |
703 class DPageWriteRequest; |
777 class DPageWriteRequest; |
704 |
778 |
705 /** |
779 /** |
706 A pool of paging requests for use by a single paging device. |
780 A pool of paging requests for use by a single paging device. |
707 */ |
781 */ |
708 class DPagingRequestPool : public DBase |
782 class DPagingRequestPool : public DBase |
709 { |
783 { |
710 public: |
784 public: |
711 DPagingRequestPool(TUint aNumPageReadRequest,TUint aNumPageWriteRequest); |
785 DPagingRequestPool(TUint aNumPageReadRequest, TBool aWriteRequest); |
712 DPageReadRequest* AcquirePageReadRequest(DMemoryObject* aMemory, TUint aIndex, TUint aCount); |
786 DPageReadRequest* AcquirePageReadRequest(DMemoryObject* aMemory, TUint aIndex, TUint aCount); |
713 DPageWriteRequest* AcquirePageWriteRequest(DMemoryObject* aMemory, TUint aIndex, TUint aCount); |
787 DPageWriteRequest* AcquirePageWriteRequest(DMemoryObject** aMemory, TUint* aIndex, TUint aCount); |
714 private: |
788 private: |
715 ~DPagingRequestPool(); |
789 ~DPagingRequestPool(); |
716 private: |
790 private: |
717 class TGroup |
791 class TGroup |
718 { |
792 { |
719 public: |
793 public: |
720 TGroup(TUint aNumRequests); |
794 TGroup(TUint aNumRequests); |
721 DPagingRequest* FindCollision(DMemoryObject* aMemory, TUint aIndex, TUint aCount); |
795 DPoolPagingRequest* FindCollisionContiguous(DMemoryObject* aMemory, TUint aIndex, TUint aCount); |
722 DPagingRequest* GetRequest(DMemoryObject* aMemory, TUint aIndex, TUint aCount); |
796 DPoolPagingRequest* GetRequest(DMemoryObject* aMemory, TUint aIndex, TUint aCount); |
723 void Signal(DPagingRequest* aRequest); |
797 void Signal(DPoolPagingRequest* aRequest); |
724 public: |
798 public: |
725 TUint iNumRequests; |
799 TUint iNumRequests; |
726 DPagingRequest** iRequests; |
800 DPoolPagingRequest** iRequests; |
727 SDblQue iFreeList; |
801 SDblQue iFreeList; |
728 }; |
802 }; |
729 TGroup iPageReadRequests; |
803 TGroup iPageReadRequests; |
730 TGroup iPageWriteRequests; |
804 DPageWriteRequest* iPageWriteRequest; |
731 |
805 |
732 friend class DPagingRequest; |
806 friend class DPoolPagingRequest; |
733 friend class DPageReadRequest; |
807 friend class DPageReadRequest; |
734 friend class DPageWriteRequest; |
808 friend class DPageWriteRequest; |
735 }; |
809 }; |
736 |
810 |
737 |
811 |
739 Resources needed to service a paging request. |
813 Resources needed to service a paging request. |
740 */ |
814 */ |
741 class DPagingRequest : public SDblQueLink |
815 class DPagingRequest : public SDblQueLink |
742 { |
816 { |
743 public: |
817 public: |
744 DPagingRequest(DPagingRequestPool::TGroup& aPoolGroup); |
818 enum |
745 void Release(); |
819 { |
|
820 EMaxPages = 4 |
|
821 }; |
|
822 DPagingRequest(); |
|
823 TLinAddr MapPages(TUint aColour, TUint aCount, TPhysAddr* aPages); |
|
824 void UnmapPages(TBool aIMBRequired); |
|
825 void SetUseContiguous(DMemoryObject* aMemory, TUint aIndex, TUint aCount); |
|
826 void SetUseDiscontiguous(DMemoryObject** aMemory, TUint* aIndex, TUint aCount); |
|
827 void ResetUse(); |
|
828 TBool CheckUseContiguous(DMemoryObject* aMemory, TUint aIndex, TUint aCount); |
|
829 TBool CheckUseDiscontiguous(DMemoryObject** aMemory, TUint* aIndex, TUint aCount); |
|
830 TBool IsCollisionContiguous(DMemoryObject* aMemory, TUint aIndex, TUint aCount); |
|
831 public: |
|
832 DMutex* iMutex; /**< A mutex for synchronisation and priority inheritance. */ |
|
833 protected: |
|
834 Mmu::TTempMapping iTempMapping; |
|
835 private: |
|
836 // used to identify memory request is used for... |
|
837 TUint iUseRegionCount; |
|
838 DMemoryObject* iUseRegionMemory[EMaxPages]; |
|
839 TUint iUseRegionIndex[EMaxPages]; |
|
840 }; |
|
841 |
|
842 |
|
843 __ASSERT_COMPILE(DPagingRequest::EMaxPages >= KMaxPagesToClean); |
|
844 |
|
845 |
|
846 /** |
|
847 A paging request that is part of a pool of similar request objects. |
|
848 */ |
|
849 class DPoolPagingRequest : public DPagingRequest |
|
850 { |
|
851 public: |
|
852 DPoolPagingRequest(DPagingRequestPool::TGroup& aPoolGroup); |
|
853 void Release(); |
746 void Wait(); |
854 void Wait(); |
747 void Signal(); |
855 void Signal(); |
748 void SetUse(DMemoryObject* aMemory, TUint aIndex, TUint aCount); |
856 public: |
749 TBool CheckUse(DMemoryObject* aMemory, TUint aIndex, TUint aCount); |
857 TInt iUsageCount; /**< How many threads are using or waiting for this object. */ |
750 TBool IsCollision(DMemoryObject* aMemory, TUint aIndex, TUint aCount); |
|
751 TLinAddr MapPages(TUint aColour, TUint aCount, TPhysAddr* aPages); |
|
752 void UnmapPages(TBool aIMBRequired); |
|
753 public: |
|
754 TThreadMessage iMessage; /**< Used by the media driver to queue requests */ |
|
755 DMutex* iMutex; /**< A mutex for synchronisation and priority inheritance. */ |
|
756 TInt iUsageCount;/**< How many threads are using or waiting for this object. */ |
|
757 TLinAddr iBuffer; /**< A buffer to read compressed data into. Size is EMaxPages+1 pages.*/ |
|
758 protected: |
|
759 Mmu::TTempMapping iTempMapping; |
|
760 private: |
858 private: |
761 DPagingRequestPool::TGroup& iPoolGroup; |
859 DPagingRequestPool::TGroup& iPoolGroup; |
762 // used to identify memory request is used for... |
|
763 DMemoryObject* iUseRegionMemory; |
|
764 TUint iUseRegionIndex; |
|
765 TUint iUseRegionCount; |
|
766 }; |
860 }; |
767 |
861 |
768 |
862 |
769 /** |
863 /** |
770 Resources needed to service a page in request. |
864 Resources needed to service a page in request. |
771 */ |
865 */ |
772 class DPageReadRequest : public DPagingRequest |
866 class DPageReadRequest : public DPoolPagingRequest |
773 { |
867 { |
774 public: |
868 public: |
775 inline DPageReadRequest(DPagingRequestPool::TGroup& aPoolGroup) |
869 DPageReadRequest(DPagingRequestPool::TGroup& aPoolGroup); |
776 : DPagingRequest(aPoolGroup) |
|
777 {} |
|
778 TInt Construct(); |
870 TInt Construct(); |
779 enum |
|
780 { |
|
781 EMaxPages = 4 |
|
782 }; |
|
783 static TUint ReservedPagesRequired(); |
871 static TUint ReservedPagesRequired(); |
784 private: |
872 private: |
785 ~DPageReadRequest(); // can't delete |
873 ~DPageReadRequest(); // can't delete |
786 public: |
874 public: |
787 TLinAddr iBuffer; /**< A buffer to read compressed data into. Size is EMaxPages+1 pages.*/ |
875 TLinAddr iBuffer; /**< A buffer to read compressed data into. Size is EMaxPages+1 pages.*/ |
802 Resources needed to service a page out request. |
890 Resources needed to service a page out request. |
803 */ |
891 */ |
804 class DPageWriteRequest : public DPagingRequest |
892 class DPageWriteRequest : public DPagingRequest |
805 { |
893 { |
806 public: |
894 public: |
807 inline DPageWriteRequest(DPagingRequestPool::TGroup& aPoolGroup) |
895 DPageWriteRequest(); |
808 : DPagingRequest(aPoolGroup) |
896 void Release(); |
809 {} |
|
810 TInt Construct(); |
|
811 enum |
|
812 { |
|
813 EMaxPages = 1 |
|
814 }; |
|
815 private: |
897 private: |
816 ~DPageWriteRequest(); // can't delete |
898 ~DPageWriteRequest(); // can't delete |
817 private: |
|
818 static TInt iAllocNext; |
|
819 }; |
899 }; |
820 |
900 |
821 |
901 |
|
902 /** |
|
903 Class providing access to the mutex used to protect page cleaning operations; |
|
904 this is the mutex DPager::iPageCleaningLock. |
|
905 */ |
|
906 class PageCleaningLock |
|
907 { |
|
908 public: |
|
909 /** |
|
910 Acquire the lock. |
|
911 The lock may be acquired multiple times by a thread, and will remain locked |
|
912 until #Unlock has been used enough times to balance this. |
|
913 */ |
|
914 static void Lock(); |
|
915 |
|
916 /** |
|
917 Release the lock. |
|
918 |
|
919 @pre The current thread has previously acquired the lock. |
|
920 */ |
|
921 static void Unlock(); |
|
922 |
|
923 /** |
|
924 Return true if the current thread holds the lock. |
|
925 This is used for debug checks. |
|
926 */ |
|
927 static TBool IsHeld(); |
|
928 |
|
929 /** |
|
930 Create the lock. |
|
931 Called by DPager::Init3(). |
|
932 */ |
|
933 static void Init(); |
|
934 }; |
|
935 |
|
936 |
822 #endif |
937 #endif |