aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorMel Gorman <mel@csn.ul.ie>2008-04-28 05:12:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-28 11:58:18 -0400
commitdd1a239f6f2d4d3eedd318583ec319aa145b324c (patch)
treeaff4224c96b5e2e67588c3946858a724863eeaf9 /include
parent54a6eb5c4765aa573a030ceeba2c14e3d2ea5706 (diff)
mm: have zonelist contains structs with both a zone pointer and zone_idx
Filtering zonelists requires very frequent use of zone_idx(). This is costly as it involves a lookup of another structure and a substraction operation. As the zone_idx is often required, it should be quickly accessible. The node idx could also be stored here if it was found that accessing zone->node is significant which may be the case on workloads where nodemasks are heavily used. This patch introduces a struct zoneref to store a zone pointer and a zone index. The zonelist then consists of an array of these struct zonerefs which are looked up as necessary. Helpers are given for accessing the zone index as well as the node index. [kamezawa.hiroyu@jp.fujitsu.com: Suggested struct zoneref instead of embedding information in pointers] [hugh@veritas.com: mm-have-zonelist: fix memcg ooms] [hugh@veritas.com: just return do_try_to_free_pages] [hugh@veritas.com: do_try_to_free_pages gfp_mask redundant] Signed-off-by: Mel Gorman <mel@csn.ul.ie> Acked-by: Christoph Lameter <clameter@sgi.com> Acked-by: David Rientjes <rientjes@google.com> Signed-off-by: Lee Schermerhorn <lee.schermerhorn@hp.com> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Mel Gorman <mel@csn.ul.ie> Cc: Christoph Lameter <clameter@sgi.com> Cc: Nick Piggin <nickpiggin@yahoo.com.au> Signed-off-by: Hugh Dickins <hugh@veritas.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include')
-rw-r--r--include/linux/mmzone.h64
-rw-r--r--include/linux/oom.h4
2 files changed, 56 insertions, 12 deletions
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index d5c33a0b89e9..d34b4c290017 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -469,6 +469,15 @@ struct zonelist_cache;
469#endif 469#endif
470 470
471/* 471/*
472 * This struct contains information about a zone in a zonelist. It is stored
473 * here to avoid dereferences into large structures and lookups of tables
474 */
475struct zoneref {
476 struct zone *zone; /* Pointer to actual zone */
477 int zone_idx; /* zone_idx(zoneref->zone) */
478};
479
480/*
472 * One allocation request operates on a zonelist. A zonelist 481 * One allocation request operates on a zonelist. A zonelist
473 * is a list of zones, the first one is the 'goal' of the 482 * is a list of zones, the first one is the 'goal' of the
474 * allocation, the other zones are fallback zones, in decreasing 483 * allocation, the other zones are fallback zones, in decreasing
@@ -476,11 +485,18 @@ struct zonelist_cache;
476 * 485 *
477 * If zlcache_ptr is not NULL, then it is just the address of zlcache, 486 * If zlcache_ptr is not NULL, then it is just the address of zlcache,
478 * as explained above. If zlcache_ptr is NULL, there is no zlcache. 487 * as explained above. If zlcache_ptr is NULL, there is no zlcache.
488 * *
489 * To speed the reading of the zonelist, the zonerefs contain the zone index
490 * of the entry being read. Helper functions to access information given
491 * a struct zoneref are
492 *
493 * zonelist_zone() - Return the struct zone * for an entry in _zonerefs
494 * zonelist_zone_idx() - Return the index of the zone for an entry
495 * zonelist_node_idx() - Return the index of the node for an entry
479 */ 496 */
480
481struct zonelist { 497struct zonelist {
482 struct zonelist_cache *zlcache_ptr; // NULL or &zlcache 498 struct zonelist_cache *zlcache_ptr; // NULL or &zlcache
483 struct zone *zones[MAX_ZONES_PER_ZONELIST + 1]; // NULL delimited 499 struct zoneref _zonerefs[MAX_ZONES_PER_ZONELIST + 1];
484#ifdef CONFIG_NUMA 500#ifdef CONFIG_NUMA
485 struct zonelist_cache zlcache; // optional ... 501 struct zonelist_cache zlcache; // optional ...
486#endif 502#endif
@@ -713,26 +729,52 @@ extern struct zone *next_zone(struct zone *zone);
713 zone; \ 729 zone; \
714 zone = next_zone(zone)) 730 zone = next_zone(zone))
715 731
732static inline struct zone *zonelist_zone(struct zoneref *zoneref)
733{
734 return zoneref->zone;
735}
736
737static inline int zonelist_zone_idx(struct zoneref *zoneref)
738{
739 return zoneref->zone_idx;
740}
741
742static inline int zonelist_node_idx(struct zoneref *zoneref)
743{
744#ifdef CONFIG_NUMA
745 /* zone_to_nid not available in this context */
746 return zoneref->zone->node;
747#else
748 return 0;
749#endif /* CONFIG_NUMA */
750}
751
752static inline void zoneref_set_zone(struct zone *zone, struct zoneref *zoneref)
753{
754 zoneref->zone = zone;
755 zoneref->zone_idx = zone_idx(zone);
756}
757
716/* Returns the first zone at or below highest_zoneidx in a zonelist */ 758/* Returns the first zone at or below highest_zoneidx in a zonelist */
717static inline struct zone **first_zones_zonelist(struct zonelist *zonelist, 759static inline struct zoneref *first_zones_zonelist(struct zonelist *zonelist,
718 enum zone_type highest_zoneidx) 760 enum zone_type highest_zoneidx)
719{ 761{
720 struct zone **z; 762 struct zoneref *z;
721 763
722 /* Find the first suitable zone to use for the allocation */ 764 /* Find the first suitable zone to use for the allocation */
723 z = zonelist->zones; 765 z = zonelist->_zonerefs;
724 while (*z && zone_idx(*z) > highest_zoneidx) 766 while (zonelist_zone_idx(z) > highest_zoneidx)
725 z++; 767 z++;
726 768
727 return z; 769 return z;
728} 770}
729 771
730/* Returns the next zone at or below highest_zoneidx in a zonelist */ 772/* Returns the next zone at or below highest_zoneidx in a zonelist */
731static inline struct zone **next_zones_zonelist(struct zone **z, 773static inline struct zoneref *next_zones_zonelist(struct zoneref *z,
732 enum zone_type highest_zoneidx) 774 enum zone_type highest_zoneidx)
733{ 775{
734 /* Find the next suitable zone to use for the allocation */ 776 /* Find the next suitable zone to use for the allocation */
735 while (*z && zone_idx(*z) > highest_zoneidx) 777 while (zonelist_zone_idx(z) > highest_zoneidx)
736 z++; 778 z++;
737 779
738 return z; 780 return z;
@@ -748,9 +790,11 @@ static inline struct zone **next_zones_zonelist(struct zone **z,
748 * This iterator iterates though all zones at or below a given zone index. 790 * This iterator iterates though all zones at or below a given zone index.
749 */ 791 */
750#define for_each_zone_zonelist(zone, z, zlist, highidx) \ 792#define for_each_zone_zonelist(zone, z, zlist, highidx) \
751 for (z = first_zones_zonelist(zlist, highidx), zone = *z++; \ 793 for (z = first_zones_zonelist(zlist, highidx), \
794 zone = zonelist_zone(z++); \
752 zone; \ 795 zone; \
753 z = next_zones_zonelist(z, highidx), zone = *z++) 796 z = next_zones_zonelist(z, highidx), \
797 zone = zonelist_zone(z++))
754 798
755#ifdef CONFIG_SPARSEMEM 799#ifdef CONFIG_SPARSEMEM
756#include <asm/sparsemem.h> 800#include <asm/sparsemem.h>
diff --git a/include/linux/oom.h b/include/linux/oom.h
index 3852436b652a..a7979baf1e39 100644
--- a/include/linux/oom.h
+++ b/include/linux/oom.h
@@ -23,8 +23,8 @@ enum oom_constraint {
23 CONSTRAINT_MEMORY_POLICY, 23 CONSTRAINT_MEMORY_POLICY,
24}; 24};
25 25
26extern int try_set_zone_oom(struct zonelist *zonelist); 26extern int try_set_zone_oom(struct zonelist *zonelist, gfp_t gfp_flags);
27extern void clear_zonelist_oom(struct zonelist *zonelist); 27extern void clear_zonelist_oom(struct zonelist *zonelist, gfp_t gfp_flags);
28 28
29extern void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order); 29extern void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order);
30extern int register_oom_notifier(struct notifier_block *nb); 30extern int register_oom_notifier(struct notifier_block *nb);